/ components / esp_http_client / esp_http_client.c
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  }