]> gitweb.ps.run Git - matrix_esp_thesis/blob - src/matrix_http_esp32.c
3faf9f5dd1aef66e5881ceaf90cacd67f89d7e05
[matrix_esp_thesis] / src / matrix_http_esp32.c
1 #include <string.h>
2 #include <sys/param.h>
3 #include <stdlib.h>
4 #include <ctype.h>
5 #include "esp_log.h"
6 #include "nvs_flash.h"
7 #include "esp_event.h"
8 #include "esp_netif.h"
9 // #include "protocol_examples_common.h"
10 // #include "protocol_examples_utils.h"
11 #include "esp_tls.h"
12 #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
13 #include "esp_crt_bundle.h"
14 #endif
15
16 #if !CONFIG_IDF_TARGET_LINUX
17 #include "freertos/FreeRTOS.h"
18 #include "freertos/task.h"
19 #include "esp_system.h"
20 #endif
21
22 #include "esp_http_client.h"
23
24 /* Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem
25
26    The PEM file was extracted from the output of this command:
27    openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
28
29    The CA root cert is the last cert given in the chain of certs.
30
31    To embed it in the app binary, the PEM file is named
32    in the component.mk COMPONENT_EMBED_TXTFILES variable.
33 */
34 // extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
35 // extern const char howsmyssl_com_root_cert_pem_end[]   asm("_binary_howsmyssl_com_root_cert_pem_end");
36
37 // extern const char postman_root_cert_pem_start[] asm("_binary_postman_root_cert_pem_start");
38 // extern const char postman_root_cert_pem_end[]   asm("_binary_postman_root_cert_pem_end");
39
40 #include "matrix.h"
41
42 #define HTTP_CONNECTION_DATA_SIZE 1024*64
43 #define AUTHORIZATION_HEADER_LEN 64
44
45 struct MatrixHttpConnection {
46     esp_http_client_handle_t client;
47
48     const char * host;
49     const char * accessToken;
50
51     // char data[HTTP_CONNECTION_DATA_SIZE];
52     char * data;
53     int dataCap;
54     int dataLen;
55 };
56
57
58 static const char *TAG = "HTTP_CLIENT";
59
60 esp_err_t _http_event_handler(esp_http_client_event_t *evt)
61 {
62     vTaskDelay(10/portTICK_PERIOD_MS);
63
64     MatrixHttpConnection * hc = (MatrixHttpConnection *)evt->user_data;
65     switch(evt->event_id) {
66         case HTTP_EVENT_ERROR:
67             ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
68             break;
69         case HTTP_EVENT_ON_CONNECTED:
70             ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
71             break;
72         case HTTP_EVENT_HEADER_SENT:
73             ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
74             break;
75         case HTTP_EVENT_ON_HEADER:
76             ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
77             break;
78         case HTTP_EVENT_ON_DATA:
79             ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
80             /*
81              *  Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
82              *  However, event handler can also be used in case chunked encoding is used.
83              */
84             if (!esp_http_client_is_chunked_response(evt->client)) {
85                 ESP_LOGD(TAG, "Non-Chunked Encoding");
86             }
87             else {
88                 ESP_LOGD(TAG, "Chunked Encoding");
89             }
90
91             int copy_len = 0;
92
93             // const int64_t buffer_len = esp_http_client_get_content_length(evt->client);
94             // if (buffer_len < hc->dataCap) {
95             //     ESP_LOGE(TAG, "Output buffer too small: %" PRIu64 ", data_len: %d", buffer_len, evt->data_len);
96             //     return ESP_FAIL;
97             // }
98             copy_len = MIN(evt->data_len, (hc->dataCap - hc->dataLen));
99             if (copy_len) {
100                 memcpy(hc->data + hc->dataLen, evt->data, copy_len);
101             }
102
103             hc->dataLen += copy_len;
104
105             break;
106         case HTTP_EVENT_ON_FINISH:
107             ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
108             break;
109         case HTTP_EVENT_DISCONNECTED:
110             ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
111             int mbedtls_err = 0;
112             esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL);
113             if (err != 0) {
114                 ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
115                 ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
116             }
117             break;
118         case HTTP_EVENT_REDIRECT:
119             ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
120             // esp_http_client_set_header(evt->client, "From", "user@example.com");
121             // esp_http_client_set_header(evt->client, "Accept", "text/html");
122             // esp_http_client_set_redirection(evt->client);
123             break;
124     }
125     return ESP_OK;
126 }
127
128 void
129 MatrixHttpConnect(
130     MatrixHttpConnection * hc)
131 {
132     esp_http_client_config_t config = {
133         .url = hc->host,
134         // .query = "esp",
135         .event_handler = _http_event_handler,
136         .user_data = hc,
137         .disable_auto_redirect = true,
138         .crt_bundle_attach = esp_crt_bundle_attach,
139     };
140
141     hc->client = esp_http_client_init(&config);
142
143     esp_http_client_set_timeout_ms(hc->client, 10000);
144 }
145
146 void
147 MatrixHttpDisconnect(
148     MatrixHttpConnection * hc)
149 {
150     esp_http_client_cleanup(hc->client);
151     hc->client = NULL;
152 }
153
154 bool
155 MatrixHttpInit(
156     MatrixHttpConnection ** hc,
157     const char * host)
158 {
159     *hc = (MatrixHttpConnection *)calloc(1, sizeof(MatrixHttpConnection));
160     
161     (*hc)->host = host;
162     (*hc)->dataLen = 0;
163
164     MatrixHttpConnect(*hc);
165
166     return true;
167 }
168
169 bool
170 MatrixHttpDeinit(
171     MatrixHttpConnection ** hc)
172 {
173     MatrixHttpDisconnect(*hc);
174
175     free(*hc);
176     *hc = NULL;
177
178     return true;
179 }
180
181 bool
182 MatrixHttpSetAccessToken(
183     MatrixHttpConnection * hc,
184     const char * accessToken)
185 {
186     hc->accessToken = accessToken;
187
188     return true;
189 }
190
191 bool
192 MatrixHttpGet(
193     MatrixHttpConnection * hc,
194     const char * url,
195     char * outResponseBuffer, int outResponseCap,
196     bool authenticated)
197 {
198     static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
199     if (authenticated)
200         snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN,
201             "Bearer %s", hc->accessToken);
202     else
203         authorizationHeader[0] = '\0';
204
205     printf("GET %s%s\n", hc->host, url);
206
207     hc->data = outResponseBuffer;
208     hc->dataCap = outResponseCap;
209     hc->dataLen = 0;
210
211     static char hostAndUrl[MAX_URL_LEN];
212     snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url);
213     
214     esp_http_client_set_url(hc->client, hostAndUrl);
215     esp_http_client_set_method(hc->client, HTTP_METHOD_GET);
216     if (authenticated)
217         esp_http_client_set_header(hc->client, "Authorization", authorizationHeader);
218     esp_err_t err = esp_http_client_perform(hc->client);
219     if (err == ESP_OK) {
220         ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %"PRIu64,
221                 esp_http_client_get_status_code(hc->client),
222                 esp_http_client_get_content_length(hc->client));
223     } else {
224         ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
225     }
226     // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen);
227
228     return true;
229 }
230
231 bool
232 MatrixHttpPost(
233     MatrixHttpConnection * hc,
234     const char * url,
235     const char * requestBuffer,
236     char * outResponseBuffer, int outResponseCap,
237     bool authenticated)
238 {
239     static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
240     if (authenticated)
241         snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN,
242             "Bearer %s", hc->accessToken);
243     else
244         authorizationHeader[0] = '\0';
245
246     printf("POST %s%s\n%s\n", hc->host, url, requestBuffer);
247
248     hc->data = outResponseBuffer;
249     hc->dataCap = outResponseCap;
250     hc->dataLen = 0;
251
252     static char hostAndUrl[MAX_URL_LEN];
253     snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url);
254     
255     esp_http_client_set_url(hc->client, hostAndUrl);
256     esp_http_client_set_method(hc->client, HTTP_METHOD_POST);
257     if (authenticated)
258         esp_http_client_set_header(hc->client, "Authorization", authorizationHeader);
259     esp_http_client_set_header(hc->client, "Content-Type", "application/json");
260     esp_http_client_set_post_field(hc->client, requestBuffer, strlen(requestBuffer));
261     esp_err_t err = esp_http_client_perform(hc->client);
262     if (err == ESP_OK) {
263         ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %"PRIu64,
264                 esp_http_client_get_status_code(hc->client),
265                 esp_http_client_get_content_length(hc->client));
266     } else {
267         ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
268     }
269     // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen);
270
271     return true;
272 }
273
274 bool
275 MatrixHttpPut(
276     MatrixHttpConnection * hc,
277     const char * url,
278     const char * requestBuffer,
279     char * outResponseBuffer, int outResponseCap,
280     bool authenticated)
281 {
282     static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
283     if (authenticated)
284         snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN,
285             "Bearer %s", hc->accessToken);
286     else
287         authorizationHeader[0] = '\0';
288
289     printf("PUT %s%s\n%s\n", hc->host, url, requestBuffer);
290
291     hc->data = outResponseBuffer;
292     hc->dataCap = outResponseCap;
293     hc->dataLen = 0;
294
295     static char hostAndUrl[MAX_URL_LEN];
296     snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url);
297     
298     esp_http_client_set_url(hc->client, hostAndUrl);
299     esp_http_client_set_method(hc->client, HTTP_METHOD_PUT);
300     if (authenticated)
301         esp_http_client_set_header(hc->client, "Authorization", authorizationHeader);
302     esp_http_client_set_header(hc->client, "Content-Type", "application/json");
303     esp_http_client_set_post_field(hc->client, requestBuffer, strlen(requestBuffer));
304     esp_err_t err = esp_http_client_perform(hc->client);
305     if (err == ESP_OK) {
306         ESP_LOGI(TAG, "HTTP PUT Status = %d, content_length = %"PRIu64,
307                 esp_http_client_get_status_code(hc->client),
308                 esp_http_client_get_content_length(hc->client));
309     } else {
310         ESP_LOGE(TAG, "HTTP PUT request failed: %s", esp_err_to_name(err));
311     }
312     // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen);
313
314     return true;
315 }