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