1+ /*
2+ * Espressif Modified MIT License
3+ *
4+ * Copyright (c) 2025 Espressif Systems (Shanghai) Co., LTD
5+ *
6+ * Permission is hereby granted for use **exclusively** with Espressif Systems products.
7+ * This includes the right to use, copy, modify, merge, publish, distribute, and sublicense
8+ * the Software, subject to the following conditions:
9+ *
10+ * 1. This Software **must be used in conjunction with Espressif Systems products**.
11+ * 2. The above copyright notice and this permission notice shall be included in all copies
12+ * or substantial portions of the Software.
13+ * 3. Redistribution of the Software in source or binary form **for use with non-Espressif products**
14+ * is strictly prohibited.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
17+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
18+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
19+ * FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21+ * DEALINGS IN THE SOFTWARE.
22+ *
23+ * SPDX-License-Identifier: MIT-ESPRESSIF
24+ */
25+
26+ #include <stdio.h>
27+ #include <string.h>
28+ #include <stdlib.h>
29+ #include <stdint.h>
30+ #include "freertos/FreeRTOS.h"
31+ #include "freertos/event_groups.h"
32+ #include "esp_log.h"
33+ #include "esp_idf_version.h"
34+ #include "esp_http_client.h"
35+ #include "http_client_request.h"
36+
37+ #define DEFAULT_HTTP_BUFFER_SIZE (1024)
38+ #define HTTP_FINISH_BIT (1 << 0)
39+ #define HTTP_TIMEOUT_MS (10000)
40+
41+ static const char * TAG = "HTTP_CLIENT_POST" ;
42+
43+ typedef struct {
44+ http_response_t * resp ;
45+ EventGroupHandle_t eg ;
46+ } http_client_ctx_t ;
47+
48+ /* HTTP event handler */
49+ static esp_err_t _http_event_handler (esp_http_client_event_t * evt )
50+ {
51+ http_client_ctx_t * ctx = (http_client_ctx_t * )evt -> user_data ;
52+ static int output_len = 0 ;
53+
54+ switch (evt -> event_id ) {
55+ case HTTP_EVENT_ERROR :
56+ ESP_LOGD (TAG , "HTTP_EVENT_ERROR" );
57+ break ;
58+
59+ case HTTP_EVENT_ON_CONNECTED :
60+ ESP_LOGD (TAG , "HTTP_EVENT_ON_CONNECTED" );
61+ break ;
62+
63+ case HTTP_EVENT_HEADER_SENT :
64+ ESP_LOGD (TAG , "HTTP_EVENT_HEADER_SENT" );
65+ break ;
66+
67+ case HTTP_EVENT_ON_HEADER :
68+ ESP_LOGD (TAG , "HTTP_EVENT_ON_HEADER, key=%s, value=%s" ,
69+ evt -> header_key , evt -> header_value );
70+ break ;
71+
72+ case HTTP_EVENT_ON_DATA :
73+ if (output_len + evt -> data_len > ctx -> resp -> body_len ) {
74+ ctx -> resp -> body = (char * )realloc (ctx -> resp -> body ,
75+ DEFAULT_HTTP_BUFFER_SIZE + ctx -> resp -> body_len );
76+ ctx -> resp -> body_len += DEFAULT_HTTP_BUFFER_SIZE ;
77+ }
78+ memcpy (ctx -> resp -> body + output_len , evt -> data , evt -> data_len );
79+ output_len += evt -> data_len ;
80+ break ;
81+
82+ case HTTP_EVENT_ON_FINISH :
83+ ESP_LOGD (TAG , "HTTP_EVENT_ON_FINISH" );
84+ output_len = 0 ;
85+ xEventGroupSetBits (ctx -> eg , HTTP_FINISH_BIT );
86+ break ;
87+
88+ case HTTP_EVENT_DISCONNECTED :
89+ ESP_LOGD (TAG , "HTTP_EVENT_DISCONNECTED" );
90+ break ;
91+
92+ case HTTP_EVENT_REDIRECT :
93+ break ;
94+ }
95+ return ESP_OK ;
96+ }
97+
98+ esp_err_t http_client_post (const char * url , http_req_header_t * header ,
99+ char * body , http_response_t * response )
100+ {
101+ esp_err_t err = ESP_OK ;
102+ esp_http_client_handle_t client = NULL ;
103+ http_response_t rsp_data = {0 };
104+ http_client_ctx_t ctx = {0 };
105+ esp_http_client_config_t config = {0 };
106+
107+ /* Initialize response buffer */
108+ rsp_data .body = (char * )calloc (1 , DEFAULT_HTTP_BUFFER_SIZE );
109+ if (!rsp_data .body ) {
110+ ESP_LOGE (TAG , "Failed to allocate response buffer" );
111+ return ESP_ERR_NO_MEM ;
112+ }
113+ rsp_data .body_len = DEFAULT_HTTP_BUFFER_SIZE ;
114+ ctx .resp = & rsp_data ;
115+ ctx .eg = xEventGroupCreate ();
116+ if (!ctx .eg ) {
117+ ESP_LOGE (TAG , "Failed to create event group" );
118+ free (rsp_data .body );
119+ return ESP_ERR_NO_MEM ;
120+ }
121+
122+ config .buffer_size_tx = 2048 ;
123+ config .url = url ;
124+ config .query = "esp" ;
125+ config .event_handler = _http_event_handler ;
126+ config .user_data = & ctx ;
127+ client = esp_http_client_init (& config );
128+ if (!client ) {
129+ ESP_LOGE (TAG , "Failed to initialize HTTP client" );
130+ goto cleanup ;
131+ }
132+ esp_http_client_set_method (client , HTTP_METHOD_POST );
133+ if (header ) {
134+ for (int i = 0 ; header [i ].key && header [i ].value ; i ++ ) {
135+ ESP_LOGD (TAG , "Setting header: %s: %s" ,
136+ header [i ].key , header [i ].value );
137+ esp_http_client_set_header (client , header [i ].key , header [i ].value );
138+ }
139+ }
140+ if (body ) {
141+ esp_http_client_set_post_field (client , body , strlen (body ));
142+ }
143+ err = esp_http_client_perform (client );
144+ if (err != ESP_OK ) {
145+ ESP_LOGE (TAG , "HTTP request failed: %s" , esp_err_to_name (err ));
146+ goto cleanup ;
147+ }
148+
149+ EventBits_t bits = xEventGroupWaitBits (ctx .eg , HTTP_FINISH_BIT ,
150+ pdTRUE , pdFALSE ,
151+ pdMS_TO_TICKS (HTTP_TIMEOUT_MS ));
152+ if (!(bits & HTTP_FINISH_BIT )) {
153+ ESP_LOGE (TAG , "HTTP request timeout" );
154+ err = ESP_ERR_TIMEOUT ;
155+ goto cleanup ;
156+ }
157+
158+ * response = rsp_data ;
159+
160+ esp_http_client_close (client );
161+ esp_http_client_cleanup (client );
162+ vEventGroupDelete (ctx .eg );
163+ return ESP_OK ;
164+
165+ cleanup :
166+ if (client ) {
167+ esp_http_client_close (client );
168+ esp_http_client_cleanup (client );
169+ }
170+ vEventGroupDelete (ctx .eg );
171+ free (rsp_data .body );
172+ return err ;
173+ }
0 commit comments