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