]> gitweb.ps.run Git - matrix_esp_thesis/blob - src/matrix_http_esp32.c
add dependencies to repo
[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                 hc->data[hc->dataLen + copy_len] = '\0';
102             }
103
104             hc->dataLen += copy_len;
105
106             break;
107         case HTTP_EVENT_ON_FINISH:
108             ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
109             break;
110         case HTTP_EVENT_DISCONNECTED:
111             ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
112             int mbedtls_err = 0;
113             esp_err_t err = esp_tls_get_and_clear_last_error((esp_tls_error_handle_t)evt->data, &mbedtls_err, NULL);
114             if (err != 0) {
115                 ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
116                 ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
117             }
118             break;
119         case HTTP_EVENT_REDIRECT:
120             ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
121             // esp_http_client_set_header(evt->client, "From", "user@example.com");
122             // esp_http_client_set_header(evt->client, "Accept", "text/html");
123             // esp_http_client_set_redirection(evt->client);
124             break;
125     }
126     return ESP_OK;
127 }
128
129 void
130 MatrixHttpConnect(
131     MatrixHttpConnection * hc)
132 {
133     esp_http_client_config_t config = {
134         .url = hc->host,
135         // .query = "esp",
136         .event_handler = _http_event_handler,
137         .user_data = hc,
138         .disable_auto_redirect = true,
139         .crt_bundle_attach = esp_crt_bundle_attach,
140     };
141
142     hc->client = esp_http_client_init(&config);
143
144     esp_http_client_set_timeout_ms(hc->client, 10000);
145 }
146
147 void
148 MatrixHttpDisconnect(
149     MatrixHttpConnection * hc)
150 {
151     esp_http_client_cleanup(hc->client);
152     hc->client = NULL;
153 }
154
155 bool
156 MatrixHttpInit(
157     MatrixHttpConnection ** hc,
158     const char * host)
159 {
160     *hc = (MatrixHttpConnection *)calloc(1, sizeof(MatrixHttpConnection));
161     
162     (*hc)->host = host;
163     (*hc)->dataLen = 0;
164
165     MatrixHttpConnect(*hc);
166
167     return true;
168 }
169
170 bool
171 MatrixHttpDeinit(
172     MatrixHttpConnection ** hc)
173 {
174     MatrixHttpDisconnect(*hc);
175
176     free(*hc);
177     *hc = NULL;
178
179     return true;
180 }
181
182 bool
183 MatrixHttpSetAccessToken(
184     MatrixHttpConnection * hc,
185     const char * accessToken)
186 {
187     hc->accessToken = accessToken;
188
189     return true;
190 }
191
192 bool
193 MatrixHttpGet(
194     MatrixHttpConnection * hc,
195     const char * url,
196     char * outResponseBuffer, int outResponseCap,
197     bool authenticated)
198 {
199     static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
200     if (authenticated)
201         snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN,
202             "Bearer %s", hc->accessToken);
203     else
204         authorizationHeader[0] = '\0';
205
206     printf("GET %s%s\n", hc->host, url);
207
208     hc->data = outResponseBuffer;
209     hc->dataCap = outResponseCap;
210     hc->dataLen = 0;
211
212     static char hostAndUrl[MAX_URL_LEN];
213     snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url);
214     
215     esp_http_client_set_url(hc->client, hostAndUrl);
216     esp_http_client_set_method(hc->client, HTTP_METHOD_GET);
217     if (authenticated)
218         esp_http_client_set_header(hc->client, "Authorization", authorizationHeader);
219     esp_err_t err = esp_http_client_perform(hc->client);
220     if (err == ESP_OK) {
221         ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %"PRIu64,
222                 esp_http_client_get_status_code(hc->client),
223                 esp_http_client_get_content_length(hc->client));
224     } else {
225         ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
226     }
227     // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen);
228
229     return true;
230 }
231
232 bool
233 MatrixHttpPost(
234     MatrixHttpConnection * hc,
235     const char * url,
236     const char * requestBuffer,
237     char * outResponseBuffer, int outResponseCap,
238     bool authenticated)
239 {
240     static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
241     if (authenticated)
242         snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN,
243             "Bearer %s", hc->accessToken);
244     else
245         authorizationHeader[0] = '\0';
246
247     printf("POST %s%s\n%s\n", hc->host, url, requestBuffer);
248
249     hc->data = outResponseBuffer;
250     hc->dataCap = outResponseCap;
251     hc->dataLen = 0;
252
253     static char hostAndUrl[MAX_URL_LEN];
254     snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url);
255     
256     esp_http_client_set_url(hc->client, hostAndUrl);
257     esp_http_client_set_method(hc->client, HTTP_METHOD_POST);
258     if (authenticated)
259         esp_http_client_set_header(hc->client, "Authorization", authorizationHeader);
260     esp_http_client_set_header(hc->client, "Content-Type", "application/json");
261     esp_http_client_set_post_field(hc->client, requestBuffer, strlen(requestBuffer));
262     esp_err_t err = esp_http_client_perform(hc->client);
263     if (err == ESP_OK) {
264         ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %"PRIu64,
265                 esp_http_client_get_status_code(hc->client),
266                 esp_http_client_get_content_length(hc->client));
267     } else {
268         ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
269     }
270     // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen);
271
272     return true;
273 }
274
275 bool
276 MatrixHttpPut(
277     MatrixHttpConnection * hc,
278     const char * url,
279     const char * requestBuffer,
280     char * outResponseBuffer, int outResponseCap,
281     bool authenticated)
282 {
283     static char authorizationHeader[AUTHORIZATION_HEADER_LEN];
284     if (authenticated)
285         snprintf(authorizationHeader, AUTHORIZATION_HEADER_LEN,
286             "Bearer %s", hc->accessToken);
287     else
288         authorizationHeader[0] = '\0';
289
290     printf("PUT %s%s\n%s\n", hc->host, url, requestBuffer);
291
292     hc->data = outResponseBuffer;
293     hc->dataCap = outResponseCap;
294     hc->dataLen = 0;
295
296     static char hostAndUrl[MAX_URL_LEN];
297     snprintf(hostAndUrl, MAX_URL_LEN, "%s%s", hc->host, url);
298     
299     esp_http_client_set_url(hc->client, hostAndUrl);
300     esp_http_client_set_method(hc->client, HTTP_METHOD_PUT);
301     if (authenticated)
302         esp_http_client_set_header(hc->client, "Authorization", authorizationHeader);
303     esp_http_client_set_header(hc->client, "Content-Type", "application/json");
304     esp_http_client_set_post_field(hc->client, requestBuffer, strlen(requestBuffer));
305     esp_err_t err = esp_http_client_perform(hc->client);
306     if (err == ESP_OK) {
307         ESP_LOGI(TAG, "HTTP PUT Status = %d, content_length = %"PRIu64,
308                 esp_http_client_get_status_code(hc->client),
309                 esp_http_client_get_content_length(hc->client));
310     } else {
311         ESP_LOGE(TAG, "HTTP PUT request failed: %s", esp_err_to_name(err));
312     }
313     // ESP_LOG_BUFFER_HEX(TAG, hc->data, hc->dataLen);
314
315     return true;
316 }