1
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
31
32
33
34
35
38
39
40
41
42
43
47
48
49
50
51
52
53
54
55
56
57
61
62
66
67
68
72
73
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
95
96
101
102
103
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
128
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
156
157
168
169
170
171
172
173
174
175
176
178
179
188
189
190
198
199
200
208
209
211
212
213
214
215
216
217
218
219
224
229
234
235
236
237
238
239
240
241
242
244
245
246
247
249
252
253
254
255
263
264
265
266
267
268
269
270
271
272
273
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
302
303
304
305
306
308
309
310
311
312
313
314
315
316
324
325
326
327
328
329
330
331
332
333
334
335
336
351
352
355
356
357
358
359
360
366
367
368
369
370
371
372
373
374
375
382
383
384
385
386
387
388
394
395
396
397
398
399
400
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
447
448
449
457
458
459
460
461
462
463
464
465
466
467
471
472
473
476
477
485
486
487
488
489
490
493
/* ... */
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "protocol_examples_utils.h"
#include "esp_tls_crypto.h"
#include <esp_http_server.h>
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_tls.h"
#include "esp_check.h"15 includes
#if !CONFIG_IDF_TARGET_LINUX
#include <esp_wifi.h>
#include <esp_system.h>
#include "nvs_flash.h"
#include "esp_eth.h"/* ... */
#endif
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
/* ... */
static const char *TAG = "example";
#if CONFIG_EXAMPLE_BASIC_AUTH
typedef struct {
char *username;
char *password;
}{...} basic_auth_info_t;
#define HTTPD_401 "401 UNAUTHORIZED"
static char *http_auth_basic(const char *username, const char *password)
{
size_t out;
char *user_info = NULL;
char *digest = NULL;
size_t n = 0;
int rc = asprintf(&user_info, "%s:%s", username, password);
if (rc < 0) {
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
return NULL;
}{...}
if (!user_info) {
ESP_LOGE(TAG, "No enough memory for user information");
return NULL;
}{...}
esp_crypto_base64_encode(NULL, 0, &n, (const unsigned char *)user_info, strlen(user_info));
/* ... */
digest = calloc(1, 6 + n + 1);
if (digest) {
strcpy(digest, "Basic ");
esp_crypto_base64_encode((unsigned char *)digest + 6, n, &out, (const unsigned char *)user_info, strlen(user_info));
}{...}
free(user_info);
return digest;
}{...}
static esp_err_t basic_auth_get_handler(httpd_req_t *req)
{
char *buf = NULL;
size_t buf_len = 0;
basic_auth_info_t *basic_auth_info = req->user_ctx;
buf_len = httpd_req_get_hdr_value_len(req, "Authorization") + 1;
if (buf_len > 1) {
buf = calloc(1, buf_len);
if (!buf) {
ESP_LOGE(TAG, "No enough memory for basic authorization");
return ESP_ERR_NO_MEM;
}{...}
if (httpd_req_get_hdr_value_str(req, "Authorization", buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG, "Found header => Authorization: %s", buf);
}{...} else {
ESP_LOGE(TAG, "No auth value received");
}{...}
char *auth_credentials = http_auth_basic(basic_auth_info->username, basic_auth_info->password);
if (!auth_credentials) {
ESP_LOGE(TAG, "No enough memory for basic authorization credentials");
free(buf);
return ESP_ERR_NO_MEM;
}{...}
if (strncmp(auth_credentials, buf, buf_len)) {
ESP_LOGE(TAG, "Not authenticated");
httpd_resp_set_status(req, HTTPD_401);
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Connection", "keep-alive");
httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"Hello\"");
httpd_resp_send(req, NULL, 0);
}{...} else {
ESP_LOGI(TAG, "Authenticated!");
char *basic_auth_resp = NULL;
httpd_resp_set_status(req, HTTPD_200);
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Connection", "keep-alive");
int rc = asprintf(&basic_auth_resp, "{\"authenticated\": true,\"user\": \"%s\"}", basic_auth_info->username);
if (rc < 0) {
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
free(auth_credentials);
return ESP_FAIL;
}{...}
if (!basic_auth_resp) {
ESP_LOGE(TAG, "No enough memory for basic authorization response");
free(auth_credentials);
free(buf);
return ESP_ERR_NO_MEM;
}{...}
httpd_resp_send(req, basic_auth_resp, strlen(basic_auth_resp));
free(basic_auth_resp);
}{...}
free(auth_credentials);
free(buf);
}{...} else {
ESP_LOGE(TAG, "No auth header received");
httpd_resp_set_status(req, HTTPD_401);
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Connection", "keep-alive");
httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"Hello\"");
httpd_resp_send(req, NULL, 0);
}{...}
return ESP_OK;
}{...}
static httpd_uri_t basic_auth = {
.uri = "/basic_auth",
.method = HTTP_GET,
.handler = basic_auth_get_handler,
}{...};
static void httpd_register_basic_auth(httpd_handle_t server)
{
basic_auth_info_t *basic_auth_info = calloc(1, sizeof(basic_auth_info_t));
if (basic_auth_info) {
basic_auth_info->username = CONFIG_EXAMPLE_BASIC_AUTH_USERNAME;
basic_auth_info->password = CONFIG_EXAMPLE_BASIC_AUTH_PASSWORD;
basic_auth.user_ctx = basic_auth_info;
httpd_register_uri_handler(server, &basic_auth);
}{...}
}{...}
/* ... */#endif
static esp_err_t hello_get_handler(httpd_req_t *req)
{
char* buf;
size_t buf_len;
/* ... */
buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
if (buf_len > 1) {
buf = malloc(buf_len);
ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG, "Found header => Host: %s", buf);
}{...}
free(buf);
}{...}
buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1;
if (buf_len > 1) {
buf = malloc(buf_len);
ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf);
}{...}
free(buf);
}{...}
buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1;
if (buf_len > 1) {
buf = malloc(buf_len);
ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf);
}{...}
free(buf);
}{...}
/* ... */
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = malloc(buf_len);
ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed");
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
ESP_LOGI(TAG, "Found URL query => %s", buf);
char param[EXAMPLE_HTTP_QUERY_KEY_MAX_LEN], dec_param[EXAMPLE_HTTP_QUERY_KEY_MAX_LEN] = {0};
if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) {
ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param);
example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN));
ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param);
}{...}
if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) {
ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param);
example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN));
ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param);
}{...}
if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) {
ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param);
example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN));
ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param);
}{...}
}{...}
free(buf);
}{...}
httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1");
httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2");
/* ... */
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
/* ... */
if (httpd_req_get_hdr_value_len(req, "Host") == 0) {
ESP_LOGI(TAG, "Request headers lost");
}{...}
return ESP_OK;
}{ ... }
static const httpd_uri_t hello = {
.uri = "/hello",
.method = HTTP_GET,
.handler = hello_get_handler,
/* ... */
.user_ctx = "Hello World!"
}{...};
static esp_err_t echo_post_handler(httpd_req_t *req)
{
char buf[100];
int ret, remaining = req->content_len;
while (remaining > 0) {
if ((ret = httpd_req_recv(req, buf,
MIN(remaining, sizeof(buf)))) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
continue;
}{...}
return ESP_FAIL;
}{...}
httpd_resp_send_chunk(req, buf, ret);
remaining -= ret;
ESP_LOGI(TAG, "=========== RECEIVED DATA ==========");
ESP_LOGI(TAG, "%.*s", ret, buf);
ESP_LOGI(TAG, "====================================");
}{...}
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}{ ... }
static const httpd_uri_t echo = {
.uri = "/echo",
.method = HTTP_POST,
.handler = echo_post_handler,
.user_ctx = NULL
}{...};
static esp_err_t any_handler(httpd_req_t *req)
{
/* ... */
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}{ ... }
static const httpd_uri_t any = {
.uri = "/any",
.method = HTTP_ANY,
.handler = any_handler,
/* ... */
.user_ctx = "Hello World!"
}{...};
/* ... */
esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
{
if (strcmp("/hello", req->uri) == 0) {
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/hello URI is not available");
return ESP_OK;
}{...} else if (strcmp("/echo", req->uri) == 0) {
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/echo URI is not available");
return ESP_FAIL;
}{...}
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Some 404 error message");
return ESP_FAIL;
}{ ... }
/* ... */
static esp_err_t ctrl_put_handler(httpd_req_t *req)
{
char buf;
int ret;
if ((ret = httpd_req_recv(req, &buf, 1)) <= 0) {
if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
httpd_resp_send_408(req);
}{...}
return ESP_FAIL;
}{...}
if (buf == '0') {
ESP_LOGI(TAG, "Unregistering /hello and /echo URIs");
httpd_unregister_uri(req->handle, "/hello");
httpd_unregister_uri(req->handle, "/echo");
httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, http_404_error_handler);
}{...}
else {
ESP_LOGI(TAG, "Registering /hello and /echo URIs");
httpd_register_uri_handler(req->handle, &hello);
httpd_register_uri_handler(req->handle, &echo);
httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, NULL);
}{...}
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}{ ... }
static const httpd_uri_t ctrl = {
.uri = "/ctrl",
.method = HTTP_PUT,
.handler = ctrl_put_handler,
.user_ctx = NULL
}{...};
static httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
#if CONFIG_IDF_TARGET_LINUX
config.server_port = 8001;/* ... */
#endif
config.lru_purge_enable = true;
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK) {
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &hello);
httpd_register_uri_handler(server, &echo);
httpd_register_uri_handler(server, &ctrl);
httpd_register_uri_handler(server, &any);
#if CONFIG_EXAMPLE_BASIC_AUTH
httpd_register_basic_auth(server);
#endif
return server;
}{...}
ESP_LOGI(TAG, "Error starting server!");
return NULL;
}{ ... }
#if !CONFIG_IDF_TARGET_LINUX
static esp_err_t stop_webserver(httpd_handle_t server)
{
return httpd_stop(server);
}{ ... }
static void disconnect_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
httpd_handle_t* server = (httpd_handle_t*) arg;
if (*server) {
ESP_LOGI(TAG, "Stopping webserver");
if (stop_webserver(*server) == ESP_OK) {
*server = NULL;
}{...} else {
ESP_LOGE(TAG, "Failed to stop http server");
}{...}
}{...}
}{ ... }
static void connect_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
httpd_handle_t* server = (httpd_handle_t*) arg;
if (*server == NULL) {
ESP_LOGI(TAG, "Starting webserver");
*server = start_webserver();
}{...}
}{ ... }
#endif/* ... */
void app_main(void)
{
static httpd_handle_t server = NULL;
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* ... */
ESP_ERROR_CHECK(example_connect());
/* ... */
#if !CONFIG_IDF_TARGET_LINUX
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));/* ... */
#endif
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));/* ... */
#endif /* ... */
#endif
server = start_webserver();
while (server) {
sleep(5);
}{...}
}{ ... }