1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <string.h>
9 
10 #include "esp_system.h"
11 #include "esp_log.h"
12 
13 #include "http_header.h"
14 #include "esp_transport.h"
15 #include "esp_transport_tcp.h"
16 #include "http_utils.h"
17 #include "http_auth.h"
18 #include "sdkconfig.h"
19 #include "esp_http_client.h"
20 #include "errno.h"
21 
22 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS
23 #include "esp_transport_ssl.h"
24 #endif
25 
26 static const char *TAG = "HTTP_CLIENT";
27 
28 /**
29  * HTTP Buffer
30  */
31 typedef struct {
32     char *data;         /*!< The HTTP data received from the server */
33     int len;            /*!< The HTTP data len received from the server */
34     char *raw_data;     /*!< The HTTP data after decoding */
35     char *orig_raw_data;/*!< The Original pointer to HTTP data after decoding */
36     int raw_len;        /*!< The HTTP data len after decoding */
37     char *output_ptr;   /*!< The destination address of the data to be copied to after decoding */
38 } esp_http_buffer_t;
39 
40 /**
41  * private HTTP Data structure
42  */
43 typedef struct {
44     http_header_handle_t headers;       /*!< http header */
45     esp_http_buffer_t   *buffer;        /*!< data buffer as linked list */
46     int                 status_code;    /*!< status code (integer) */
47     int                 content_length; /*!< data length */
48     int                 chunk_length;   /*!< chunk length */
49     int                 data_offset;    /*!< offset to http data (Skip header) */
50     int                 data_process;   /*!< data processed */
51     int                 method;         /*!< http method */
52     bool                is_chunked;
53 } esp_http_data_t;
54 
55 typedef struct {
56     char                         *url;
57     char                         *scheme;
58     char                         *host;
59     int                          port;
60     char                         *username;
61     char                         *password;
62     char                         *path;
63     char                         *query;
64     char                         *cert_pem;
65     esp_http_client_method_t     method;
66     esp_http_client_auth_type_t  auth_type;
67     esp_http_client_transport_t  transport_type;
68     int                          max_store_header_size;
69 } connection_info_t;
70 
71 typedef enum {
72     HTTP_STATE_UNINIT = 0,
73     HTTP_STATE_INIT,
74     HTTP_STATE_CONNECTED,
75     HTTP_STATE_REQ_COMPLETE_HEADER,
76     HTTP_STATE_REQ_COMPLETE_DATA,
77     HTTP_STATE_RES_COMPLETE_HEADER,
78     HTTP_STATE_RES_ON_DATA_START,
79     HTTP_STATE_RES_COMPLETE_DATA,
80     HTTP_STATE_CLOSE
81 } esp_http_state_t;
82 /**
83  * HTTP client class
84  */
85 struct esp_http_client {
86     int                         redirect_counter;
87     int                         max_redirection_count;
88     int                         max_authorization_retries;
89     int                         process_again;
90     struct http_parser          *parser;
91     struct http_parser_settings *parser_settings;
92     esp_transport_list_handle_t     transport_list;
93     esp_transport_handle_t          transport;
94     esp_http_data_t                 *request;
95     esp_http_data_t                 *response;
96     void                        *user_data;
97     esp_http_auth_data_t        *auth_data;
98     char                        *post_data;
99     char                        *location;
100     char                        *auth_header;
101     char                        *current_header_key;
102     char                        *current_header_value;
103     int                         post_len;
104     connection_info_t           connection_info;
105     bool                        is_chunk_complete;
106     esp_http_state_t            state;
107     http_event_handle_cb        event_handler;
108     int                         timeout_ms;
109     int                         buffer_size_rx;
110     int                         buffer_size_tx;
111     bool                        disable_auto_redirect;
112     esp_http_client_event_t     event;
113     int                         data_written_index;
114     int                         data_write_left;
115     bool                        first_line_prepared;
116     int                         header_index;
117     bool                        is_async;
118     esp_transport_keep_alive_t  keep_alive_cfg;
119     struct ifreq                *if_name;
120     unsigned                    cache_data_in_fetch_hdr: 1;
121 };
122 
123 typedef struct esp_http_client esp_http_client_t;
124 
125 static esp_err_t _clear_connection_info(esp_http_client_handle_t client);
126 /**
127  * Default settings
128  */
129 #define DEFAULT_HTTP_PORT (80)
130 #define DEFAULT_HTTPS_PORT (443)
131 
132 #define ASYNC_TRANS_CONNECT_FAIL -1
133 #define ASYNC_TRANS_CONNECTING 0
134 #define ASYNC_TRANS_CONNECT_PASS 1
135 
136 static const char *DEFAULT_HTTP_USER_AGENT = "ESP32 HTTP Client/1.0";
137 static const char *DEFAULT_HTTP_PROTOCOL = "HTTP/1.1";
138 static const char *DEFAULT_HTTP_PATH = "/";
139 static const int DEFAULT_MAX_REDIRECT = 10;
140 static const int DEFAULT_MAX_AUTH_RETRIES = 10;
141 static const int DEFAULT_TIMEOUT_MS = 5000;
142 static const int DEFAULT_KEEP_ALIVE_IDLE = 5;
143 static const int DEFAULT_KEEP_ALIVE_INTERVAL= 5;
144 static const int DEFAULT_KEEP_ALIVE_COUNT= 3;
145 
146 static const char *HTTP_METHOD_MAPPING[] = {
147     "GET",
148     "POST",
149     "PUT",
150     "PATCH",
151     "DELETE",
152     "HEAD",
153     "NOTIFY",
154     "SUBSCRIBE",
155     "UNSUBSCRIBE",
156     "OPTIONS",
157     "COPY",
158     "MOVE",
159     "LOCK",
160     "UNLOCK",
161     "PROPFIND",
162     "PROPPATCH",
163     "MKCOL"
164 };
165 
166 static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len);
167 static esp_err_t esp_http_client_connect(esp_http_client_handle_t client);
168 static esp_err_t esp_http_client_send_post_data(esp_http_client_handle_t client);
169 
http_dispatch_event(esp_http_client_t * client,esp_http_client_event_id_t event_id,void * data,int len)170 static esp_err_t http_dispatch_event(esp_http_client_t *client, esp_http_client_event_id_t event_id, void *data, int len)
171 {
172     esp_http_client_event_t *event = &client->event;
173 
174     if (client->event_handler) {
175         event->event_id = event_id;
176         event->user_data = client->user_data;
177         event->data = data;
178         event->data_len = len;
179         return client->event_handler(event);
180     }
181     return ESP_OK;
182 }
183 
http_on_message_begin(http_parser * parser)184 static int http_on_message_begin(http_parser *parser)
185 {
186     esp_http_client_t *client = parser->data;
187     ESP_LOGD(TAG, "on_message_begin");
188 
189     client->response->is_chunked = false;
190     client->is_chunk_complete = false;
191     return 0;
192 }
193 
http_on_url(http_parser * parser,const char * at,size_t length)194 static int http_on_url(http_parser *parser, const char *at, size_t length)
195 {
196     ESP_LOGD(TAG, "http_on_url");
197     return 0;
198 }
199 
http_on_status(http_parser * parser,const char * at,size_t length)200 static int http_on_status(http_parser *parser, const char *at, size_t length)
201 {
202     return 0;
203 }
204 
http_on_header_event(esp_http_client_handle_t client)205 static int http_on_header_event(esp_http_client_handle_t client)
206 {
207     if (client->current_header_key != NULL && client->current_header_value != NULL) {
208         ESP_LOGD(TAG, "HEADER=%s:%s", client->current_header_key, client->current_header_value);
209         client->event.header_key = client->current_header_key;
210         client->event.header_value = client->current_header_value;
211         http_dispatch_event(client, HTTP_EVENT_ON_HEADER, NULL, 0);
212         free(client->current_header_key);
213         free(client->current_header_value);
214         client->current_header_key = NULL;
215         client->current_header_value = NULL;
216     }
217     return 0;
218 }
219 
http_on_header_field(http_parser * parser,const char * at,size_t length)220 static int http_on_header_field(http_parser *parser, const char *at, size_t length)
221 {
222     esp_http_client_t *client = parser->data;
223     http_on_header_event(client);
224     http_utils_append_string(&client->current_header_key, at, length);
225 
226     return 0;
227 }
228 
http_on_header_value(http_parser * parser,const char * at,size_t length)229 static int http_on_header_value(http_parser *parser, const char *at, size_t length)
230 {
231     esp_http_client_handle_t client = parser->data;
232     if (client->current_header_key == NULL) {
233         return 0;
234     }
235     if (strcasecmp(client->current_header_key, "Location") == 0) {
236         http_utils_append_string(&client->location, at, length);
237     } else if (strcasecmp(client->current_header_key, "Transfer-Encoding") == 0
238                && memcmp(at, "chunked", length) == 0) {
239         client->response->is_chunked = true;
240     } else if (strcasecmp(client->current_header_key, "WWW-Authenticate") == 0) {
241         http_utils_append_string(&client->auth_header, at, length);
242     }
243     http_utils_append_string(&client->current_header_value, at, length);
244     return 0;
245 }
246 
http_on_headers_complete(http_parser * parser)247 static int http_on_headers_complete(http_parser *parser)
248 {
249     esp_http_client_handle_t client = parser->data;
250     http_on_header_event(client);
251     client->response->status_code = parser->status_code;
252     client->response->data_offset = parser->nread;
253     client->response->content_length = parser->content_length;
254     client->response->data_process = 0;
255     ESP_LOGD(TAG, "http_on_headers_complete, status=%d, offset=%d, nread=%d", parser->status_code, client->response->data_offset, parser->nread);
256     client->state = HTTP_STATE_RES_COMPLETE_HEADER;
257     if (client->connection_info.method == HTTP_METHOD_HEAD) {
258         /* In a HTTP_RESPONSE parser returning '1' from on_headers_complete will tell the
259            parser that it should not expect a body. This is used when receiving a response
260            to a HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: chunked'
261            headers that indicate the presence of a body.*/
262         return 1;
263     }
264     return 0;
265 }
266 
http_on_body(http_parser * parser,const char * at,size_t length)267 static int http_on_body(http_parser *parser, const char *at, size_t length)
268 {
269     esp_http_client_t *client = parser->data;
270     ESP_LOGD(TAG, "http_on_body %d", length);
271 
272     if (client->response->buffer->output_ptr) {
273         memcpy(client->response->buffer->output_ptr, (char *)at, length);
274         client->response->buffer->output_ptr += length;
275     } else {
276         /* Do not cache body when http_on_body is called from esp_http_client_perform */
277         if (client->state < HTTP_STATE_RES_ON_DATA_START && client->cache_data_in_fetch_hdr) {
278             ESP_LOGI(TAG, "Body received in fetch header state, %p, %d", at, length);
279             esp_http_buffer_t *res_buffer = client->response->buffer;
280             assert(res_buffer->orig_raw_data == res_buffer->raw_data);
281             res_buffer->orig_raw_data = (char *)realloc(res_buffer->orig_raw_data, res_buffer->raw_len + length);
282             if (!res_buffer->orig_raw_data) {
283                 ESP_LOGE(TAG, "Failed to allocate memory for storing decoded data");
284                 return -1;
285             }
286             memcpy(res_buffer->orig_raw_data + res_buffer->raw_len, at, length);
287             res_buffer->raw_data = res_buffer->orig_raw_data;
288         }
289     }
290 
291     client->response->data_process += length;
292     client->response->buffer->raw_len += length;
293     http_dispatch_event(client, HTTP_EVENT_ON_DATA, (void *)at, length);
294     return 0;
295 }
296 
http_on_message_complete(http_parser * parser)297 static int http_on_message_complete(http_parser *parser)
298 {
299     ESP_LOGD(TAG, "http_on_message_complete, parser=%x", (int)parser);
300     esp_http_client_handle_t client = parser->data;
301     client->is_chunk_complete = true;
302     return 0;
303 }
304 
http_on_chunk_complete(http_parser * parser)305 static int http_on_chunk_complete(http_parser *parser)
306 {
307     ESP_LOGD(TAG, "http_on_chunk_complete");
308     return 0;
309 }
310 
http_on_chunk_header(http_parser * parser)311 static int http_on_chunk_header(http_parser *parser)
312 {
313     esp_http_client_handle_t client = parser->data;
314     client->response->chunk_length = parser->content_length;
315     ESP_LOGD(TAG, "http_on_chunk_header, chunk_length");
316     return 0;
317 }
318 
esp_http_client_set_header(esp_http_client_handle_t client,const char * key,const char * value)319 esp_err_t esp_http_client_set_header(esp_http_client_handle_t client, const char *key, const char *value)
320 {
321     return http_header_set(client->request->headers, key, value);
322 }
323 
esp_http_client_get_header(esp_http_client_handle_t client,const char * key,char ** value)324 esp_err_t esp_http_client_get_header(esp_http_client_handle_t client, const char *key, char **value)
325 {
326     return http_header_get(client->request->headers, key, value);
327 }
328 
esp_http_client_delete_header(esp_http_client_handle_t client,const char * key)329 esp_err_t esp_http_client_delete_header(esp_http_client_handle_t client, const char *key)
330 {
331     return http_header_delete(client->request->headers, key);
332 }
333 
esp_http_client_get_username(esp_http_client_handle_t client,char ** value)334 esp_err_t esp_http_client_get_username(esp_http_client_handle_t client, char **value)
335 {
336     if (client == NULL || value == NULL) {
337         ESP_LOGE(TAG, "client or value must not be NULL");
338         return ESP_ERR_INVALID_ARG;
339     }
340     *value = client->connection_info.username;
341     return ESP_OK;
342 }
343 
esp_http_client_set_username(esp_http_client_handle_t client,const char * username)344 esp_err_t esp_http_client_set_username(esp_http_client_handle_t client, const char *username)
345 {
346     if (client == NULL) {
347         ESP_LOGE(TAG, "client must not be NULL");
348         return ESP_ERR_INVALID_ARG;
349     }
350     if (client->connection_info.username != NULL) {
351         free(client->connection_info.username);
352     }
353     client->connection_info.username = username ? strdup(username) : NULL;
354     return ESP_OK;
355 }
356 
esp_http_client_get_password(esp_http_client_handle_t client,char ** value)357 esp_err_t esp_http_client_get_password(esp_http_client_handle_t client, char **value)
358 {
359     if (client == NULL || value == NULL) {
360         ESP_LOGE(TAG, "client or value must not be NULL");
361         return ESP_ERR_INVALID_ARG;
362     }
363     *value = client->connection_info.password;
364     return ESP_OK;
365 }
366 
esp_http_client_set_password(esp_http_client_handle_t client,const char * password)367 esp_err_t esp_http_client_set_password(esp_http_client_handle_t client, const char *password)
368 {
369     if (client == NULL) {
370         ESP_LOGE(TAG, "client must not be NULL");
371         return ESP_ERR_INVALID_ARG;
372     }
373     if (client->connection_info.password != NULL) {
374         memset(client->connection_info.password, 0, strlen(client->connection_info.password));
375         free(client->connection_info.password);
376     }
377     client->connection_info.password = password ? strdup(password) : NULL;
378     return ESP_OK;
379 }
380 
esp_http_client_set_authtype(esp_http_client_handle_t client,esp_http_client_auth_type_t auth_type)381 esp_err_t esp_http_client_set_authtype(esp_http_client_handle_t client, esp_http_client_auth_type_t auth_type)
382 {
383     if (client == NULL) {
384         ESP_LOGE(TAG, "client must not be NULL");
385         return ESP_ERR_INVALID_ARG;
386     }
387     client->connection_info.auth_type = auth_type;
388     return ESP_OK;
389 }
390 
_set_config(esp_http_client_handle_t client,const esp_http_client_config_t * config)391 static esp_err_t _set_config(esp_http_client_handle_t client, const esp_http_client_config_t *config)
392 {
393     client->connection_info.method = config->method;
394     client->connection_info.port = config->port;
395     client->connection_info.auth_type = config->auth_type;
396     client->event_handler = config->event_handler;
397     client->timeout_ms = config->timeout_ms;
398     client->max_redirection_count = config->max_redirection_count;
399     client->max_authorization_retries = config->max_authorization_retries;
400     client->user_data = config->user_data;
401     client->buffer_size_rx = config->buffer_size;
402     client->buffer_size_tx = config->buffer_size_tx;
403     client->disable_auto_redirect = config->disable_auto_redirect;
404 
405     if (config->buffer_size == 0) {
406         client->buffer_size_rx = DEFAULT_HTTP_BUF_SIZE;
407     }
408 
409     if (config->buffer_size_tx == 0) {
410         client->buffer_size_tx = DEFAULT_HTTP_BUF_SIZE;
411     }
412 
413     if (client->max_redirection_count == 0) {
414         client->max_redirection_count = DEFAULT_MAX_REDIRECT;
415     }
416 
417     if (client->max_authorization_retries == 0) {
418         client->max_authorization_retries = DEFAULT_MAX_AUTH_RETRIES;
419     } else if (client->max_authorization_retries == -1) {
420         client->max_authorization_retries = 0;
421     }
422 
423     if (config->path) {
424         client->connection_info.path = strdup(config->path);
425     } else {
426         client->connection_info.path = strdup(DEFAULT_HTTP_PATH);
427     }
428     HTTP_MEM_CHECK(TAG, client->connection_info.path, {
429         return ESP_ERR_NO_MEM;
430     });
431 
432     if (config->host) {
433         client->connection_info.host = strdup(config->host);
434 
435         HTTP_MEM_CHECK(TAG, client->connection_info.host, {
436             _clear_connection_info(client);
437             return ESP_ERR_NO_MEM;
438         });
439     }
440 
441     if (config->query) {
442         client->connection_info.query = strdup(config->query);
443         HTTP_MEM_CHECK(TAG, client->connection_info.query, {
444             _clear_connection_info(client);
445             return ESP_ERR_NO_MEM;
446         });
447     }
448 
449     if (config->username) {
450         client->connection_info.username = strdup(config->username);
451         HTTP_MEM_CHECK(TAG, client->connection_info.username, {
452             _clear_connection_info(client);
453             return ESP_ERR_NO_MEM;
454         });
455     }
456 
457     if (config->password) {
458         client->connection_info.password = strdup(config->password);
459         HTTP_MEM_CHECK(TAG, client->connection_info.password, {
460             _clear_connection_info(client);
461             return ESP_ERR_NO_MEM;
462         });
463     }
464 
465     if (config->transport_type == HTTP_TRANSPORT_OVER_SSL) {
466         http_utils_assign_string(&client->connection_info.scheme, "https", -1);
467         if (client->connection_info.port == 0) {
468             client->connection_info.port = DEFAULT_HTTPS_PORT;
469         }
470     } else {
471         http_utils_assign_string(&client->connection_info.scheme, "http", -1);
472         if (client->connection_info.port == 0) {
473             client->connection_info.port = DEFAULT_HTTP_PORT;
474         }
475     }
476     if (client->timeout_ms == 0) {
477         client->timeout_ms = DEFAULT_TIMEOUT_MS;
478     }
479     if (config->is_async) {
480         client->is_async = true;
481     }
482 
483     return ESP_OK;
484 }
485 
_clear_connection_info(esp_http_client_handle_t client)486 static esp_err_t _clear_connection_info(esp_http_client_handle_t client)
487 {
488     free(client->connection_info.path);
489     free(client->connection_info.host);
490     free(client->connection_info.query);
491     free(client->connection_info.username);
492     if (client->connection_info.password) {
493         memset(client->connection_info.password, 0, strlen(client->connection_info.password));
494         free(client->connection_info.password);
495     }
496     free(client->connection_info.scheme);
497     free(client->connection_info.url);
498     memset(&client->connection_info, 0, sizeof(connection_info_t));
499     return ESP_OK;
500 }
501 
_clear_auth_data(esp_http_client_handle_t client)502 static esp_err_t _clear_auth_data(esp_http_client_handle_t client)
503 {
504     if (client->auth_data == NULL) {
505         return ESP_FAIL;
506     }
507 
508     free(client->auth_data->method);
509     free(client->auth_data->realm);
510     free(client->auth_data->algorithm);
511     free(client->auth_data->qop);
512     free(client->auth_data->nonce);
513     free(client->auth_data->opaque);
514     memset(client->auth_data, 0, sizeof(esp_http_auth_data_t));
515     return ESP_OK;
516 }
517 
esp_http_client_prepare(esp_http_client_handle_t client)518 static esp_err_t esp_http_client_prepare(esp_http_client_handle_t client)
519 {
520     client->process_again = 0;
521     client->response->data_process = 0;
522     client->first_line_prepared = false;
523     http_parser_init(client->parser, HTTP_RESPONSE);
524     if (client->connection_info.username) {
525         char *auth_response = NULL;
526 
527         if (client->connection_info.auth_type == HTTP_AUTH_TYPE_BASIC) {
528             auth_response = http_auth_basic(client->connection_info.username, client->connection_info.password);
529 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH
530         } else if (client->connection_info.auth_type == HTTP_AUTH_TYPE_DIGEST && client->auth_data) {
531             client->auth_data->uri = client->connection_info.path;
532             client->auth_data->cnonce = ((uint64_t)esp_random() << 32) + esp_random();
533             auth_response = http_auth_digest(client->connection_info.username, client->connection_info.password, client->auth_data);
534             client->auth_data->nc ++;
535 #endif
536         }
537 
538         if (auth_response) {
539             ESP_LOGD(TAG, "auth_response=%s", auth_response);
540             esp_http_client_set_header(client, "Authorization", auth_response);
541             free(auth_response);
542         }
543     }
544     return ESP_OK;
545 }
546 
_get_host_header(char * host,int port)547 static char *_get_host_header(char *host, int port)
548 {
549     int err = 0;
550     char *host_name;
551     if (port != DEFAULT_HTTP_PORT && port != DEFAULT_HTTPS_PORT) {
552         err = asprintf(&host_name, "%s:%d", host, port);
553     } else {
554         err = asprintf(&host_name, "%s", host);
555     }
556     if (err == -1) {
557         return NULL;
558     }
559     return host_name;
560 }
561 
esp_http_client_init(const esp_http_client_config_t * config)562 esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *config)
563 {
564 
565     esp_http_client_handle_t client;
566     esp_transport_handle_t tcp = NULL;
567     char *host_name;
568     bool _success;
569 
570     _success = (
571                    (client                         = calloc(1, sizeof(esp_http_client_t)))           &&
572                    (client->parser                 = calloc(1, sizeof(struct http_parser)))          &&
573                    (client->parser_settings        = calloc(1, sizeof(struct http_parser_settings))) &&
574                    (client->auth_data              = calloc(1, sizeof(esp_http_auth_data_t)))        &&
575                    (client->request                = calloc(1, sizeof(esp_http_data_t)))             &&
576                    (client->request->headers       = http_header_init())                             &&
577                    (client->request->buffer        = calloc(1, sizeof(esp_http_buffer_t)))           &&
578                    (client->response               = calloc(1, sizeof(esp_http_data_t)))             &&
579                    (client->response->headers      = http_header_init())                             &&
580                    (client->response->buffer       = calloc(1, sizeof(esp_http_buffer_t)))
581                );
582 
583     if (!_success) {
584         ESP_LOGE(TAG, "Error allocate memory");
585         goto error;
586     }
587 
588     _success = (
589                    (client->transport_list = esp_transport_list_init()) &&
590                    (tcp = esp_transport_tcp_init()) &&
591                    (esp_transport_set_default_port(tcp, DEFAULT_HTTP_PORT) == ESP_OK) &&
592                    (esp_transport_list_add(client->transport_list, tcp, "http") == ESP_OK)
593                );
594     if (!_success) {
595         ESP_LOGE(TAG, "Error initialize transport");
596         goto error;
597     }
598 
599     if (config->keep_alive_enable == true) {
600         client->keep_alive_cfg.keep_alive_enable = true;
601         client->keep_alive_cfg.keep_alive_idle = (config->keep_alive_idle == 0) ? DEFAULT_KEEP_ALIVE_IDLE : config->keep_alive_idle;
602         client->keep_alive_cfg.keep_alive_interval = (config->keep_alive_interval == 0) ? DEFAULT_KEEP_ALIVE_INTERVAL : config->keep_alive_interval;
603         client->keep_alive_cfg.keep_alive_count =  (config->keep_alive_count == 0) ? DEFAULT_KEEP_ALIVE_COUNT : config->keep_alive_count;
604         esp_transport_tcp_set_keep_alive(tcp, &client->keep_alive_cfg);
605     }
606 
607     if (config->if_name) {
608         client->if_name = calloc(1, sizeof(struct ifreq) + 1);
609         HTTP_MEM_CHECK(TAG, client->if_name, goto error);
610         memcpy(client->if_name, config->if_name, sizeof(struct ifreq));
611         esp_transport_tcp_set_interface_name(tcp, client->if_name);
612     }
613 
614 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS
615     esp_transport_handle_t ssl = NULL;
616     _success = (
617                    (ssl = esp_transport_ssl_init()) &&
618                    (esp_transport_set_default_port(ssl, DEFAULT_HTTPS_PORT) == ESP_OK) &&
619                    (esp_transport_list_add(client->transport_list, ssl, "https") == ESP_OK)
620                );
621 
622     if (!_success) {
623         ESP_LOGE(TAG, "Error initialize SSL Transport");
624         goto error;
625     }
626 
627     if (config->crt_bundle_attach != NULL) {
628 #ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
629         esp_transport_ssl_crt_bundle_attach(ssl, config->crt_bundle_attach);
630 #else //CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
631         ESP_LOGE(TAG, "use_crt_bundle configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option");
632 #endif
633     } else if (config->use_global_ca_store == true) {
634         esp_transport_ssl_enable_global_ca_store(ssl);
635     } else if (config->cert_pem) {
636         if (!config->cert_len) {
637             esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
638         } else {
639             esp_transport_ssl_set_cert_data_der(ssl, config->cert_pem, config->cert_len);
640         }
641     }
642 
643     if (config->client_cert_pem) {
644         if (!config->client_cert_len) {
645             esp_transport_ssl_set_client_cert_data(ssl, config->client_cert_pem, strlen(config->client_cert_pem));
646         } else {
647             esp_transport_ssl_set_client_cert_data_der(ssl, config->client_cert_pem, config->client_cert_len);
648         }
649     }
650 
651     if (config->client_key_pem) {
652         if (!config->client_key_len) {
653             esp_transport_ssl_set_client_key_data(ssl, config->client_key_pem, strlen(config->client_key_pem));
654         } else {
655             esp_transport_ssl_set_client_key_data_der(ssl, config->client_key_pem, config->client_key_len);
656         }
657     }
658 
659     if (config->client_key_password && config->client_key_password_len > 0) {
660         esp_transport_ssl_set_client_key_password(ssl, config->client_key_password, config->client_key_password_len);
661     }
662 
663     if (config->skip_cert_common_name_check) {
664         esp_transport_ssl_skip_common_name_check(ssl);
665     }
666 #endif
667 
668     if (_set_config(client, config) != ESP_OK) {
669         ESP_LOGE(TAG, "Error set configurations");
670         goto error;
671     }
672     _success = (
673                    (client->request->buffer->data  = malloc(client->buffer_size_tx))  &&
674                    (client->response->buffer->data = malloc(client->buffer_size_rx))
675                );
676 
677     if (!_success) {
678         ESP_LOGE(TAG, "Allocation failed");
679         goto error;
680     }
681 
682     const char *user_agent = config->user_agent == NULL ? DEFAULT_HTTP_USER_AGENT : config->user_agent;
683 
684     if (config->host != NULL && config->path != NULL) {
685         if (client->connection_info.host == NULL) {
686             ESP_LOGE(TAG, "invalid host");
687             goto error;
688         }
689         host_name = _get_host_header(client->connection_info.host, client->connection_info.port);
690         if (host_name == NULL) {
691             ESP_LOGE(TAG, "Failed to allocate memory for host header");
692             goto error;
693         }
694         _success = (
695             (esp_http_client_set_header(client, "User-Agent", user_agent) == ESP_OK) &&
696             (esp_http_client_set_header(client, "Host", host_name) == ESP_OK)
697         );
698         free(host_name);
699         if (!_success) {
700             ESP_LOGE(TAG, "Error while setting default configurations");
701             goto error;
702         }
703     } else if (config->url != NULL) {
704         if (esp_http_client_set_url(client, config->url) != ESP_OK) {
705             ESP_LOGE(TAG, "Failed to set URL");
706             goto error;
707         }
708         if (client->connection_info.host == NULL) {
709             ESP_LOGE(TAG, "invalid host");
710             goto error;
711         }
712         host_name = _get_host_header(client->connection_info.host, client->connection_info.port);
713         if (host_name == NULL) {
714             ESP_LOGE(TAG, "Failed to allocate memory for host header");
715             goto error;
716         }
717 
718         _success = (
719                     (esp_http_client_set_header(client, "User-Agent", user_agent) == ESP_OK) &&
720                     (esp_http_client_set_header(client, "Host", host_name) == ESP_OK)
721                 );
722 
723         free(host_name);
724         if (!_success) {
725             ESP_LOGE(TAG, "Error while setting default configurations");
726             goto error;
727         }
728     } else {
729         ESP_LOGE(TAG, "config should have either URL or host & path");
730         goto error;
731     }
732 
733     /* As default behavior, cache data received in fetch header state. This will be
734      * used in esp_http_client_read API only. For esp_http_perform we shall disable
735      * this as data will be processed by event handler */
736     client->cache_data_in_fetch_hdr = 1;
737 
738     client->parser_settings->on_message_begin = http_on_message_begin;
739     client->parser_settings->on_url = http_on_url;
740     client->parser_settings->on_status = http_on_status;
741     client->parser_settings->on_header_field = http_on_header_field;
742     client->parser_settings->on_header_value = http_on_header_value;
743     client->parser_settings->on_headers_complete = http_on_headers_complete;
744     client->parser_settings->on_body = http_on_body;
745     client->parser_settings->on_message_complete = http_on_message_complete;
746     client->parser_settings->on_chunk_complete = http_on_chunk_complete;
747     client->parser_settings->on_chunk_header = http_on_chunk_header;
748     client->parser->data = client;
749     client->event.client = client;
750 
751     client->state = HTTP_STATE_INIT;
752     return client;
753 error:
754     esp_http_client_cleanup(client);
755     return NULL;
756 }
757 
esp_http_client_cleanup(esp_http_client_handle_t client)758 esp_err_t esp_http_client_cleanup(esp_http_client_handle_t client)
759 {
760     if (client == NULL) {
761         return ESP_FAIL;
762     }
763     esp_http_client_close(client);
764     if (client->transport_list) {
765         esp_transport_list_destroy(client->transport_list);
766     }
767     if (client->request) {
768         http_header_destroy(client->request->headers);
769         if (client->request->buffer) {
770             free(client->request->buffer->data);
771         }
772         free(client->request->buffer);
773         free(client->request);
774     }
775     if (client->response) {
776         http_header_destroy(client->response->headers);
777         if (client->response->buffer) {
778             free(client->response->buffer->data);
779             if (client->response->buffer->orig_raw_data) {
780                 free(client->response->buffer->orig_raw_data);
781                 client->response->buffer->orig_raw_data = NULL;
782                 client->response->buffer->raw_data = NULL;
783             }
784         }
785         free(client->response->buffer);
786         free(client->response);
787     }
788     if (client->if_name) {
789         free(client->if_name);
790     }
791     free(client->parser);
792     free(client->parser_settings);
793     _clear_connection_info(client);
794     _clear_auth_data(client);
795     free(client->auth_data);
796     free(client->current_header_key);
797     free(client->location);
798     free(client->auth_header);
799     free(client);
800     return ESP_OK;
801 }
802 
esp_http_client_set_redirection(esp_http_client_handle_t client)803 esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client)
804 {
805     if (client == NULL) {
806         return ESP_ERR_INVALID_ARG;
807     }
808     if (client->location == NULL) {
809         return ESP_ERR_INVALID_ARG;
810     }
811     ESP_LOGD(TAG, "Redirect to %s", client->location);
812     return esp_http_client_set_url(client, client->location);
813 }
814 
esp_http_check_response(esp_http_client_handle_t client)815 static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
816 {
817     if (client->response->status_code >= HttpStatus_Ok && client->response->status_code < HttpStatus_MultipleChoices) {
818         return ESP_OK;
819     }
820     if (client->redirect_counter >= client->max_redirection_count || client->disable_auto_redirect) {
821         ESP_LOGE(TAG, "Error, reach max_redirection_count count=%d", client->redirect_counter);
822         return ESP_ERR_HTTP_MAX_REDIRECT;
823     }
824     switch (client->response->status_code) {
825         case HttpStatus_MovedPermanently:
826         case HttpStatus_Found:
827         case HttpStatus_TemporaryRedirect:
828             esp_http_client_set_redirection(client);
829             client->redirect_counter ++;
830             client->process_again = 1;
831             break;
832         case HttpStatus_Unauthorized:
833             esp_http_client_add_auth(client);
834     }
835     return ESP_OK;
836 }
837 
esp_http_client_set_url(esp_http_client_handle_t client,const char * url)838 esp_err_t esp_http_client_set_url(esp_http_client_handle_t client, const char *url)
839 {
840     char *old_host = NULL;
841     struct http_parser_url purl;
842     int old_port;
843 
844     if (client == NULL || url == NULL) {
845         ESP_LOGE(TAG, "client or url must not NULL");
846         return ESP_ERR_INVALID_ARG;
847     }
848 
849     http_parser_url_init(&purl);
850 
851     int parser_status = http_parser_parse_url(url, strlen(url), 0, &purl);
852 
853     if (parser_status != 0) {
854         ESP_LOGE(TAG, "Error parse url %s", url);
855         return ESP_ERR_INVALID_ARG;
856     }
857     if (client->connection_info.host) {
858         old_host = strdup(client->connection_info.host);
859     }
860     old_port = client->connection_info.port;
861 
862     if (purl.field_data[UF_HOST].len) {
863         http_utils_assign_string(&client->connection_info.host, url + purl.field_data[UF_HOST].off, purl.field_data[UF_HOST].len);
864         HTTP_MEM_CHECK(TAG, client->connection_info.host, {
865             free(old_host);
866             return ESP_ERR_NO_MEM;
867         });
868     }
869     // Close the connection if host was changed
870     if (old_host && client->connection_info.host
871             && strcasecmp(old_host, (const void *)client->connection_info.host) != 0) {
872         ESP_LOGD(TAG, "New host assign = %s", client->connection_info.host);
873         if (esp_http_client_set_header(client, "Host", client->connection_info.host) != ESP_OK) {
874             free(old_host);
875             return ESP_ERR_NO_MEM;
876         }
877         esp_http_client_close(client);
878     }
879 
880     if (old_host) {
881         free(old_host);
882         old_host = NULL;
883     }
884 
885     if (purl.field_data[UF_SCHEMA].len) {
886         http_utils_assign_string(&client->connection_info.scheme, url + purl.field_data[UF_SCHEMA].off, purl.field_data[UF_SCHEMA].len);
887         HTTP_MEM_CHECK(TAG, client->connection_info.scheme, return ESP_ERR_NO_MEM);
888 
889         if (strcasecmp(client->connection_info.scheme, "http") == 0) {
890             client->connection_info.port = DEFAULT_HTTP_PORT;
891         } else if (strcasecmp(client->connection_info.scheme, "https") == 0) {
892             client->connection_info.port = DEFAULT_HTTPS_PORT;
893         }
894     }
895 
896     if (purl.field_data[UF_PORT].len) {
897         client->connection_info.port = strtol((const char*)(url + purl.field_data[UF_PORT].off), NULL, 10);
898     }
899 
900     if (old_port != client->connection_info.port) {
901         esp_http_client_close(client);
902     }
903 
904     if (purl.field_data[UF_USERINFO].len) {
905         char *user_info = NULL;
906         http_utils_assign_string(&user_info, url + purl.field_data[UF_USERINFO].off, purl.field_data[UF_USERINFO].len);
907         if (user_info) {
908             char *username = user_info;
909             char *password = strchr(user_info, ':');
910             if (password) {
911                 *password = 0;
912                 password ++;
913                 http_utils_assign_string(&client->connection_info.password, password, -1);
914                 HTTP_MEM_CHECK(TAG, client->connection_info.password, return ESP_ERR_NO_MEM);
915             }
916             http_utils_assign_string(&client->connection_info.username, username, -1);
917             HTTP_MEM_CHECK(TAG, client->connection_info.username, return ESP_ERR_NO_MEM);
918             free(user_info);
919         } else {
920             return ESP_ERR_NO_MEM;
921         }
922     }
923 
924     //Reset path and query if there are no information
925     if (purl.field_data[UF_PATH].len) {
926         http_utils_assign_string(&client->connection_info.path, url + purl.field_data[UF_PATH].off, purl.field_data[UF_PATH].len);
927     } else {
928         http_utils_assign_string(&client->connection_info.path, "/", -1);
929     }
930     HTTP_MEM_CHECK(TAG, client->connection_info.path, return ESP_ERR_NO_MEM);
931 
932     if (purl.field_data[UF_QUERY].len) {
933         http_utils_assign_string(&client->connection_info.query, url + purl.field_data[UF_QUERY].off, purl.field_data[UF_QUERY].len);
934         HTTP_MEM_CHECK(TAG, client->connection_info.query, return ESP_ERR_NO_MEM);
935     } else if (client->connection_info.query) {
936         free(client->connection_info.query);
937         client->connection_info.query = NULL;
938     }
939 
940     return ESP_OK;
941 }
942 
esp_http_client_get_errno(esp_http_client_handle_t client)943 int esp_http_client_get_errno(esp_http_client_handle_t client)
944 {
945     if (!client) {
946         ESP_LOGE(TAG, "Invalid client handle");
947         return -1;
948     }
949     return esp_transport_get_errno(client->transport);
950 }
951 
esp_http_client_set_method(esp_http_client_handle_t client,esp_http_client_method_t method)952 esp_err_t esp_http_client_set_method(esp_http_client_handle_t client, esp_http_client_method_t method)
953 {
954     client->connection_info.method = method;
955     return ESP_OK;
956 }
957 
esp_http_client_set_timeout_ms(esp_http_client_handle_t client,int timeout_ms)958 esp_err_t esp_http_client_set_timeout_ms(esp_http_client_handle_t client, int timeout_ms)
959 {
960     if (client == NULL) {
961         return ESP_ERR_INVALID_ARG;
962     }
963 
964     client->timeout_ms = timeout_ms;
965     return ESP_OK;
966 }
967 
esp_http_client_get_data(esp_http_client_handle_t client)968 static int esp_http_client_get_data(esp_http_client_handle_t client)
969 {
970     if (client->state < HTTP_STATE_RES_ON_DATA_START) {
971         return ESP_FAIL;
972     }
973 
974     if (client->connection_info.method == HTTP_METHOD_HEAD) {
975         return 0;
976     }
977 
978     esp_http_buffer_t *res_buffer = client->response->buffer;
979 
980     ESP_LOGD(TAG, "data_process=%d, content_length=%d", client->response->data_process, client->response->content_length);
981 
982     int rlen = esp_transport_read(client->transport, res_buffer->data, client->buffer_size_rx, client->timeout_ms);
983     if (rlen >= 0) {
984         http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen);
985     }
986     return rlen;
987 }
988 
esp_http_client_is_complete_data_received(esp_http_client_handle_t client)989 bool esp_http_client_is_complete_data_received(esp_http_client_handle_t client)
990 {
991     if (client->response->is_chunked) {
992         if (!client->is_chunk_complete) {
993             ESP_LOGD(TAG, "Chunks were not completely read");
994             return false;
995         }
996     } else {
997         if (client->response->data_process != client->response->content_length) {
998             ESP_LOGD(TAG, "Data processed %d != Data specified in content length %d", client->response->data_process, client->response->content_length);
999             return false;
1000         }
1001     }
1002     return true;
1003 }
1004 
esp_http_client_read(esp_http_client_handle_t client,char * buffer,int len)1005 int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len)
1006 {
1007     esp_http_buffer_t *res_buffer = client->response->buffer;
1008 
1009     int rlen = ESP_FAIL, ridx = 0;
1010     if (res_buffer->raw_len) {
1011         int remain_len = client->response->buffer->raw_len;
1012         if (remain_len > len) {
1013             remain_len = len;
1014         }
1015         memcpy(buffer, res_buffer->raw_data, remain_len);
1016         res_buffer->raw_len -= remain_len;
1017         res_buffer->raw_data += remain_len;
1018         ridx = remain_len;
1019         if (res_buffer->raw_len == 0) {
1020             free(res_buffer->orig_raw_data);
1021             res_buffer->orig_raw_data = NULL;
1022             res_buffer->raw_data = NULL;
1023         }
1024     }
1025     int need_read = len - ridx;
1026     bool is_data_remain = true;
1027     while (need_read > 0 && is_data_remain) {
1028         if (client->response->is_chunked) {
1029             is_data_remain = !client->is_chunk_complete;
1030         } else {
1031             is_data_remain = client->response->data_process < client->response->content_length;
1032         }
1033         ESP_LOGD(TAG, "is_data_remain=%d, is_chunked=%d, content_length=%d", is_data_remain, client->response->is_chunked, client->response->content_length);
1034         if (!is_data_remain) {
1035             break;
1036         }
1037         int byte_to_read = need_read;
1038         if (byte_to_read > client->buffer_size_rx) {
1039             byte_to_read = client->buffer_size_rx;
1040         }
1041         errno = 0;
1042         rlen = esp_transport_read(client->transport, res_buffer->data, byte_to_read, client->timeout_ms);
1043         ESP_LOGD(TAG, "need_read=%d, byte_to_read=%d, rlen=%d, ridx=%d", need_read, byte_to_read, rlen, ridx);
1044 
1045         if (rlen <= 0) {
1046             if (errno != 0) {
1047                 esp_log_level_t sev = ESP_LOG_WARN;
1048                 /* On connection close from server, recv should ideally return 0 but we have error conversion
1049                  * in `tcp_transport` SSL layer which translates it `-1` and hence below additional checks */
1050                 if (rlen == -1 && errno == ENOTCONN && client->response->is_chunked) {
1051                     /* Explicit call to parser for invoking `message_complete` callback */
1052                     http_parser_execute(client->parser, client->parser_settings, res_buffer->data, 0);
1053                     /* ...and lowering the message severity, as closed connection from server side is expected in chunked transport */
1054                     sev = ESP_LOG_DEBUG;
1055                 }
1056                 ESP_LOG_LEVEL(sev, TAG, "esp_transport_read returned:%d and errno:%d ", rlen, errno);
1057             }
1058 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS
1059             if (rlen == ESP_TLS_ERR_SSL_WANT_READ || errno == EAGAIN) {
1060 #else
1061             if (errno == EAGAIN) {
1062 #endif
1063                 ESP_LOGD(TAG, "Received EAGAIN! rlen = %d, errno %d", rlen, errno);
1064                 return ridx;
1065             }
1066             if (rlen < 0 && ridx == 0 && !esp_http_client_is_complete_data_received(client)) {
1067                 http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1068                 return ESP_FAIL;
1069             }
1070             return ridx;
1071         }
1072         res_buffer->output_ptr = buffer + ridx;
1073         http_parser_execute(client->parser, client->parser_settings, res_buffer->data, rlen);
1074         ridx += res_buffer->raw_len;
1075         need_read -= res_buffer->raw_len;
1076 
1077         res_buffer->raw_len = 0; //clear
1078         res_buffer->output_ptr = NULL;
1079     }
1080 
1081     return ridx;
1082 }
1083 
1084 esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
1085 {
1086     esp_err_t err;
1087     do {
1088         if (client->process_again) {
1089             esp_http_client_prepare(client);
1090         }
1091         switch (client->state) {
1092         /* In case of blocking esp_http_client_perform(), the following states will fall through one after the after;
1093            in case of non-blocking esp_http_client_perform(), if there is an error condition, like EINPROGRESS or EAGAIN,
1094            then the esp_http_client_perform() API will return ESP_ERR_HTTP_EAGAIN error. The user may call
1095            esp_http_client_perform API again, and for this reason, we maintain the states */
1096             case HTTP_STATE_INIT:
1097                 if ((err = esp_http_client_connect(client)) != ESP_OK) {
1098                     if (client->is_async && err == ESP_ERR_HTTP_CONNECTING) {
1099                         return ESP_ERR_HTTP_EAGAIN;
1100                     }
1101                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1102                     return err;
1103                 }
1104                 /* falls through */
1105             case HTTP_STATE_CONNECTED:
1106                 if ((err = esp_http_client_request_send(client, client->post_len)) != ESP_OK) {
1107                     if (client->is_async && errno == EAGAIN) {
1108                         return ESP_ERR_HTTP_EAGAIN;
1109                     }
1110                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1111                     return err;
1112                 }
1113                 /* falls through */
1114             case HTTP_STATE_REQ_COMPLETE_HEADER:
1115                 if ((err = esp_http_client_send_post_data(client)) != ESP_OK) {
1116                     if (client->is_async && errno == EAGAIN) {
1117                         return ESP_ERR_HTTP_EAGAIN;
1118                     }
1119                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1120                     return err;
1121                 }
1122                 /* falls through */
1123             case HTTP_STATE_REQ_COMPLETE_DATA:
1124                 /* Disable caching response body, as data should
1125                  * be handled by application event handler */
1126                 client->cache_data_in_fetch_hdr = 0;
1127                 if (esp_http_client_fetch_headers(client) < 0) {
1128                     if (client->is_async && errno == EAGAIN) {
1129                         return ESP_ERR_HTTP_EAGAIN;
1130                     }
1131                     /* Enable caching after error condition because next
1132                      * request could be performed using native APIs */
1133                     client->cache_data_in_fetch_hdr = 1;
1134                     if (esp_transport_get_errno(client->transport) == ENOTCONN) {
1135                         ESP_LOGW(TAG, "Close connection due to FIN received");
1136                         esp_http_client_close(client);
1137                         http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1138                         return ESP_ERR_HTTP_CONNECTION_CLOSED;
1139                     }
1140                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1141                     return ESP_ERR_HTTP_FETCH_HEADER;
1142                 }
1143                 /* falls through */
1144             case HTTP_STATE_RES_ON_DATA_START:
1145                 /* Enable caching after fetch headers state because next
1146                  * request could be performed using native APIs */
1147                 client->cache_data_in_fetch_hdr = 1;
1148                 if ((err = esp_http_check_response(client)) != ESP_OK) {
1149                     ESP_LOGE(TAG, "Error response");
1150                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1151                     return err;
1152                 }
1153                 while (client->response->is_chunked && !client->is_chunk_complete) {
1154                     if (esp_http_client_get_data(client) <= 0) {
1155                         if (client->is_async && errno == EAGAIN) {
1156                             return ESP_ERR_HTTP_EAGAIN;
1157                         }
1158                         ESP_LOGD(TAG, "Read finish or server requests close");
1159                         break;
1160                     }
1161                 }
1162                 while (client->response->data_process < client->response->content_length) {
1163                     if (esp_http_client_get_data(client) <= 0) {
1164                         if (client->is_async && errno == EAGAIN) {
1165                             return ESP_ERR_HTTP_EAGAIN;
1166                         }
1167                         ESP_LOGD(TAG, "Read finish or server requests close");
1168                         break;
1169                     }
1170                 }
1171                 http_dispatch_event(client, HTTP_EVENT_ON_FINISH, NULL, 0);
1172 
1173                 client->response->buffer->raw_len = 0;
1174                 if (!http_should_keep_alive(client->parser)) {
1175                     ESP_LOGD(TAG, "Close connection");
1176                     esp_http_client_close(client);
1177                 } else {
1178                     if (client->state > HTTP_STATE_CONNECTED) {
1179                         client->state = HTTP_STATE_CONNECTED;
1180                         client->first_line_prepared = false;
1181                     }
1182                 }
1183                 break;
1184                 default:
1185                 break;
1186         }
1187     } while (client->process_again);
1188     return ESP_OK;
1189 }
1190 
1191 int esp_http_client_fetch_headers(esp_http_client_handle_t client)
1192 {
1193     if (client->state < HTTP_STATE_REQ_COMPLETE_HEADER) {
1194         return ESP_FAIL;
1195     }
1196 
1197     client->state = HTTP_STATE_REQ_COMPLETE_DATA;
1198     esp_http_buffer_t *buffer = client->response->buffer;
1199     client->response->status_code = -1;
1200 
1201     while (client->state < HTTP_STATE_RES_COMPLETE_HEADER) {
1202         buffer->len = esp_transport_read(client->transport, buffer->data, client->buffer_size_rx, client->timeout_ms);
1203         if (buffer->len <= 0) {
1204             return ESP_FAIL;
1205         }
1206         http_parser_execute(client->parser, client->parser_settings, buffer->data, buffer->len);
1207     }
1208     client->state = HTTP_STATE_RES_ON_DATA_START;
1209     ESP_LOGD(TAG, "content_length = %d", client->response->content_length);
1210     if (client->response->content_length <= 0) {
1211         client->response->is_chunked = true;
1212         return 0;
1213     }
1214     return client->response->content_length;
1215 }
1216 
1217 static esp_err_t esp_http_client_connect(esp_http_client_handle_t client)
1218 {
1219     esp_err_t err;
1220 
1221     if (client->state == HTTP_STATE_UNINIT) {
1222         ESP_LOGE(TAG, "Client has not been initialized");
1223         return ESP_ERR_INVALID_STATE;
1224     }
1225 
1226     if ((err = esp_http_client_prepare(client)) != ESP_OK) {
1227         ESP_LOGE(TAG, "Failed to initialize request data");
1228         esp_http_client_close(client);
1229         return err;
1230     }
1231 
1232     if (client->state < HTTP_STATE_CONNECTED) {
1233         ESP_LOGD(TAG, "Begin connect to: %s://%s:%d", client->connection_info.scheme, client->connection_info.host, client->connection_info.port);
1234         client->transport = esp_transport_list_get_transport(client->transport_list, client->connection_info.scheme);
1235         if (client->transport == NULL) {
1236             ESP_LOGE(TAG, "No transport found");
1237 #ifndef CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS
1238             if (strcasecmp(client->connection_info.scheme, "https") == 0) {
1239                 ESP_LOGE(TAG, "Please enable HTTPS at menuconfig to allow requesting via https");
1240             }
1241 #endif
1242             return ESP_ERR_HTTP_INVALID_TRANSPORT;
1243         }
1244         if (!client->is_async) {
1245             if (esp_transport_connect(client->transport, client->connection_info.host, client->connection_info.port, client->timeout_ms) < 0) {
1246                 ESP_LOGE(TAG, "Connection failed, sock < 0");
1247                 return ESP_ERR_HTTP_CONNECT;
1248             }
1249         } else {
1250             int ret = esp_transport_connect_async(client->transport, client->connection_info.host, client->connection_info.port, client->timeout_ms);
1251             if (ret == ASYNC_TRANS_CONNECT_FAIL) {
1252                 ESP_LOGE(TAG, "Connection failed");
1253                 if (strcasecmp(client->connection_info.scheme, "http") == 0) {
1254                     ESP_LOGE(TAG, "Asynchronous mode doesn't work for HTTP based connection");
1255                     return ESP_ERR_INVALID_ARG;
1256                 }
1257                 return ESP_ERR_HTTP_CONNECT;
1258             } else if (ret == ASYNC_TRANS_CONNECTING) {
1259                 ESP_LOGD(TAG, "Connection not yet established");
1260                 return ESP_ERR_HTTP_CONNECTING;
1261             }
1262         }
1263         client->state = HTTP_STATE_CONNECTED;
1264         http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0);
1265     }
1266     return ESP_OK;
1267 }
1268 
1269 static int http_client_prepare_first_line(esp_http_client_handle_t client, int write_len)
1270 {
1271     if (write_len >= 0) {
1272         http_header_set_format(client->request->headers, "Content-Length", "%d", write_len);
1273     } else {
1274         esp_http_client_set_header(client, "Transfer-Encoding", "chunked");
1275     }
1276 
1277     const char *method = HTTP_METHOD_MAPPING[client->connection_info.method];
1278 
1279     int first_line_len = snprintf(client->request->buffer->data,
1280                                   client->buffer_size_tx, "%s %s",
1281                                   method,
1282                                   client->connection_info.path);
1283     if (first_line_len >= client->buffer_size_tx) {
1284         ESP_LOGE(TAG, "Out of buffer");
1285         return -1;
1286     }
1287 
1288     if (client->connection_info.query) {
1289         first_line_len += snprintf(client->request->buffer->data + first_line_len,
1290                                    client->buffer_size_tx - first_line_len, "?%s", client->connection_info.query);
1291         if (first_line_len >= client->buffer_size_tx) {
1292             ESP_LOGE(TAG, "Out of buffer");
1293             return -1;
1294 
1295         }
1296     }
1297     first_line_len += snprintf(client->request->buffer->data + first_line_len,
1298                                client->buffer_size_tx - first_line_len, " %s\r\n", DEFAULT_HTTP_PROTOCOL);
1299     if (first_line_len >= client->buffer_size_tx) {
1300         ESP_LOGE(TAG, "Out of buffer");
1301         return -1;
1302     }
1303     return first_line_len;
1304 }
1305 
1306 static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, int write_len)
1307 {
1308     int first_line_len = 0;
1309     if (!client->first_line_prepared) {
1310         if ((first_line_len = http_client_prepare_first_line(client, write_len)) < 0) {
1311             return first_line_len;
1312         }
1313         client->first_line_prepared = true;
1314         client->header_index = 0;
1315         client->data_written_index = 0;
1316         client->data_write_left = 0;
1317     }
1318 
1319     if (client->data_write_left > 0) {
1320         /* sending leftover data from previous call to esp_http_client_request_send() API */
1321         int wret = 0;
1322         if (((wret = esp_http_client_write(client, client->request->buffer->data + client->data_written_index, client->data_write_left)) < 0)) {
1323             ESP_LOGE(TAG, "Error write request");
1324             return ESP_ERR_HTTP_WRITE_DATA;
1325         }
1326         client->data_write_left -= wret;
1327         client->data_written_index += wret;
1328         if (client->is_async && client->data_write_left > 0) {
1329             return ESP_ERR_HTTP_WRITE_DATA;      /* In case of EAGAIN error, we return ESP_ERR_HTTP_WRITE_DATA,
1330                                                  and the handling of EAGAIN should be done in the higher level APIs. */
1331         }
1332     }
1333 
1334     int wlen = client->buffer_size_tx - first_line_len;
1335     while ((client->header_index = http_header_generate_string(client->request->headers, client->header_index, client->request->buffer->data + first_line_len, &wlen))) {
1336         if (wlen <= 0) {
1337             break;
1338         }
1339         if (first_line_len) {
1340             wlen += first_line_len;
1341             first_line_len = 0;
1342         }
1343         client->request->buffer->data[wlen] = 0;
1344         ESP_LOGD(TAG, "Write header[%d]: %s", client->header_index, client->request->buffer->data);
1345 
1346         client->data_write_left = wlen;
1347         client->data_written_index = 0;
1348         while (client->data_write_left > 0) {
1349             int wret = esp_transport_write(client->transport, client->request->buffer->data + client->data_written_index, client->data_write_left, client->timeout_ms);
1350             if (wret <= 0) {
1351                 ESP_LOGE(TAG, "Error write request");
1352                 esp_http_client_close(client);
1353                 return ESP_ERR_HTTP_WRITE_DATA;
1354             }
1355             client->data_write_left -= wret;
1356             client->data_written_index += wret;
1357         }
1358         wlen = client->buffer_size_tx;
1359     }
1360 
1361     client->data_written_index = 0;
1362     client->data_write_left = client->post_len;
1363     http_dispatch_event(client, HTTP_EVENT_HEADERS_SENT, NULL, 0);
1364     client->state = HTTP_STATE_REQ_COMPLETE_HEADER;
1365     return ESP_OK;
1366 }
1367 
1368 static esp_err_t esp_http_client_send_post_data(esp_http_client_handle_t client)
1369 {
1370     if (client->state != HTTP_STATE_REQ_COMPLETE_HEADER) {
1371         ESP_LOGE(TAG, "Invalid state");
1372         return ESP_ERR_INVALID_STATE;
1373     }
1374     if (!(client->post_data && client->post_len)) {
1375         goto success;
1376     }
1377 
1378     int wret = esp_http_client_write(client, client->post_data + client->data_written_index, client->data_write_left);
1379     if (wret < 0) {
1380         return wret;
1381     }
1382     client->data_write_left -= wret;
1383     client->data_written_index += wret;
1384 
1385     if (client->data_write_left <= 0) {
1386         goto success;
1387     } else {
1388         return ESP_ERR_HTTP_WRITE_DATA;
1389     }
1390 
1391 success:
1392     client->state = HTTP_STATE_REQ_COMPLETE_DATA;
1393     return ESP_OK;
1394 }
1395 
1396 esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
1397 {
1398     client->post_len = write_len;
1399     esp_err_t err;
1400     if ((err = esp_http_client_connect(client)) != ESP_OK) {
1401         http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1402         return err;
1403     }
1404     if ((err = esp_http_client_request_send(client, write_len)) != ESP_OK) {
1405         http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
1406         return err;
1407     }
1408     return ESP_OK;
1409 }
1410 
1411 int esp_http_client_write(esp_http_client_handle_t client, const char *buffer, int len)
1412 {
1413     if (client->state < HTTP_STATE_REQ_COMPLETE_HEADER) {
1414         return ESP_FAIL;
1415     }
1416 
1417     int wlen = 0, widx = 0;
1418     while (len > 0) {
1419         wlen = esp_transport_write(client->transport, buffer + widx, len, client->timeout_ms);
1420         /* client->async_block is initialised in case of non-blocking IO, and in this case we return how
1421            much ever data was written by the esp_transport_write() API. */
1422         if (client->is_async || wlen <= 0) {
1423             return wlen;
1424         }
1425         widx += wlen;
1426         len -= wlen;
1427     }
1428     return widx;
1429 }
1430 
1431 esp_err_t esp_http_client_close(esp_http_client_handle_t client)
1432 {
1433     if (client->state >= HTTP_STATE_INIT) {
1434         http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0);
1435         client->state = HTTP_STATE_INIT;
1436         return esp_transport_close(client->transport);
1437     }
1438     return ESP_OK;
1439 }
1440 
1441 esp_err_t esp_http_client_set_post_field(esp_http_client_handle_t client, const char *data, int len)
1442 {
1443     esp_err_t err = ESP_OK;
1444     client->post_data = (char *)data;
1445     client->post_len = len;
1446     ESP_LOGD(TAG, "set post file length = %d", len);
1447     if (client->post_data) {
1448         char *value = NULL;
1449         if ((err = esp_http_client_get_header(client, "Content-Type", &value)) != ESP_OK) {
1450             return err;
1451         }
1452         if (value == NULL) {
1453             err = esp_http_client_set_header(client, "Content-Type", "application/x-www-form-urlencoded");
1454         }
1455     } else {
1456         client->post_len = 0;
1457         err = esp_http_client_set_header(client, "Content-Type", NULL);
1458     }
1459     return err;
1460 }
1461 
1462 int esp_http_client_get_post_field(esp_http_client_handle_t client, char **data)
1463 {
1464     if (client->post_data) {
1465         *data = client->post_data;
1466         return client->post_len;
1467     }
1468     return 0;
1469 }
1470 
1471 int esp_http_client_get_status_code(esp_http_client_handle_t client)
1472 {
1473     return client->response->status_code;
1474 }
1475 
1476 int esp_http_client_get_content_length(esp_http_client_handle_t client)
1477 {
1478     return client->response->content_length;
1479 }
1480 
1481 bool esp_http_client_is_chunked_response(esp_http_client_handle_t client)
1482 {
1483     return client->response->is_chunked;
1484 }
1485 
1486 esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_handle_t client)
1487 {
1488     if (!strcasecmp(client->connection_info.scheme, "https") ) {
1489         return HTTP_TRANSPORT_OVER_SSL;
1490     } else if (!strcasecmp(client->connection_info.scheme, "http")) {
1491         return HTTP_TRANSPORT_OVER_TCP;
1492     } else {
1493         return HTTP_TRANSPORT_UNKNOWN;
1494     }
1495 }
1496 
1497 void esp_http_client_add_auth(esp_http_client_handle_t client)
1498 {
1499     if (client == NULL) {
1500         return;
1501     }
1502     if (client->state != HTTP_STATE_RES_ON_DATA_START) {
1503         return;
1504     }
1505     if (client->redirect_counter >= client->max_authorization_retries) {
1506         ESP_LOGE(TAG, "Error, reached max_authorization_retries count=%d", client->redirect_counter);
1507         return;
1508     }
1509 
1510     char *auth_header = client->auth_header;
1511     if (auth_header) {
1512         http_utils_trim_whitespace(&auth_header);
1513         ESP_LOGD(TAG, "UNAUTHORIZED: %s", auth_header);
1514         client->redirect_counter++;
1515 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH
1516         if (http_utils_str_starts_with(auth_header, "Digest") == 0) {
1517             ESP_LOGD(TAG, "type = Digest");
1518             client->connection_info.auth_type = HTTP_AUTH_TYPE_DIGEST;
1519         } else {
1520 #endif
1521 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
1522         if (http_utils_str_starts_with(auth_header, "Basic") == 0) {
1523             ESP_LOGD(TAG, "type = Basic");
1524             client->connection_info.auth_type = HTTP_AUTH_TYPE_BASIC;
1525         } else {
1526 #endif
1527             client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
1528             ESP_LOGE(TAG, "This authentication method is not supported: %s", auth_header);
1529             return;
1530 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH
1531         }
1532 #endif
1533 #ifdef CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH
1534         }
1535 #endif
1536 
1537         _clear_auth_data(client);
1538 
1539         client->auth_data->method = strdup(HTTP_METHOD_MAPPING[client->connection_info.method]);
1540 
1541         client->auth_data->nc = 1;
1542         client->auth_data->realm = http_utils_get_string_between(auth_header, "realm=\"", "\"");
1543         client->auth_data->algorithm = http_utils_get_string_between(auth_header, "algorithm=", ",");
1544         if (client->auth_data->algorithm == NULL) {
1545             client->auth_data->algorithm = strdup("MD5");
1546         }
1547         client->auth_data->qop = http_utils_get_string_between(auth_header, "qop=\"", "\"");
1548         client->auth_data->nonce = http_utils_get_string_between(auth_header, "nonce=\"", "\"");
1549         client->auth_data->opaque = http_utils_get_string_between(auth_header, "opaque=\"", "\"");
1550         client->process_again = 1;
1551     } else {
1552         client->connection_info.auth_type = HTTP_AUTH_TYPE_NONE;
1553         ESP_LOGW(TAG, "This request requires authentication, but does not provide header information for that");
1554     }
1555 }
1556 
1557 int esp_http_client_read_response(esp_http_client_handle_t client, char *buffer, int len)
1558 {
1559     int read_len = 0;
1560     while (read_len < len) {
1561         int data_read = esp_http_client_read(client, buffer + read_len, len - read_len);
1562         if (data_read <= 0) {
1563             return read_len;
1564         }
1565         read_len += data_read;
1566     }
1567     return read_len;
1568 }
1569 
1570 esp_err_t esp_http_client_flush_response(esp_http_client_handle_t client, int *len)
1571 {
1572     if (client == NULL) {
1573         ESP_LOGE(TAG, "client must not be NULL");
1574         return ESP_ERR_INVALID_ARG;
1575     }
1576     int read_len = 0;
1577     while (!esp_http_client_is_complete_data_received(client)) {
1578         int data_read = esp_http_client_get_data(client);
1579         if (data_read < 0) {
1580             return ESP_FAIL;
1581         }
1582         read_len += data_read;
1583     }
1584     if (len) {
1585         *len = read_len;
1586     }
1587     return ESP_OK;
1588 }
1589 
1590 esp_err_t esp_http_client_get_url(esp_http_client_handle_t client, char *url, const int len)
1591 {
1592     if (client == NULL || url == NULL) {
1593         return ESP_ERR_INVALID_ARG;
1594     }
1595     if (client->connection_info.host && client->connection_info.scheme && client->connection_info.path) {
1596         snprintf(url, len, "%s://%s%s", client->connection_info.scheme, client->connection_info.host, client->connection_info.path);
1597         return ESP_OK;
1598     } else {
1599         ESP_LOGE(TAG, "Failed to get URL");
1600     }
1601     return ESP_FAIL;
1602 }
1603 
1604 esp_err_t esp_http_client_get_chunk_length(esp_http_client_handle_t client, int *len)
1605 {
1606     if (client == NULL || len == NULL) {
1607         return ESP_ERR_INVALID_ARG;
1608     }
1609     if (esp_http_client_is_chunked_response(client)) {
1610         *len = client->response->chunk_length;
1611     } else {
1612         ESP_LOGE(TAG, "Response is not chunked");
1613         return ESP_FAIL;
1614     }
1615     return ESP_OK;
1616 }
1617