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