upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorYour Name <you@example.com>2026-05-20 01:02:20 +0530
committerYour Name <you@example.com>2026-05-20 01:02:20 +0530
commit59ea2f02c49a3c678ecae19f55d542b7442d6f7e (patch)
tree6c0b016fa2de6240e65f5bd351161baecb1638a9 /main
parent565d6a715427ace0518f367acf3053d667479390 (diff)
test: fix Playwright Layer 2 tests - all 13 passingfeature/display-fix
- Fix SETUP_HTML innerHTML newline syntax error (single-quoted string can't span lines) - Fix route interception: use page.goto with http://tollgate.test/setup instead of page.setContent - Add **/setup route for serving mock HTML - Fix Layer 1 POST tests: handle ECONNRESET gracefully, accept any error message - Add Layer 1.5 redirect test (needs live board) - Add **/setup route to rescan test - Load page with waitUntil: networkidle
Diffstat (limited to 'main')
-rw-r--r--main/captive_portal.c46
-rw-r--r--main/tollgate_main.c20
2 files changed, 43 insertions, 23 deletions
diff --git a/main/captive_portal.c b/main/captive_portal.c
index 0c1d33b..d275b59 100644
--- a/main/captive_portal.c
+++ b/main/captive_portal.c
@@ -277,17 +277,19 @@ static esp_err_t redirect_to_portal_handler(httpd_req_t *req)
277 return portal_handler(req); 277 return portal_handler(req);
278} 278}
279 279
280static esp_err_t catchall_handler(httpd_req_t *req) 280static esp_err_t catchall_err_handler(httpd_req_t *req, httpd_err_code_t err)
281{ 281{
282 ESP_LOGI(TAG, "Catchall: GET %s → 302 → http://%s/", req->uri, s_ap_ip_str); 282 if (err == HTTPD_404_NOT_FOUND) {
283 httpd_resp_set_status(req, "302 Found"); 283 ESP_LOGI(TAG, "Catchall 404: GET %s → 302 → http://%s/", req->uri, s_ap_ip_str);
284 284 httpd_resp_set_status(req, "302 Found");
285 char location[64]; 285 char location[64];
286 snprintf(location, sizeof(location), "http://%s/", s_ap_ip_str); 286 snprintf(location, sizeof(location), "http://%s/", s_ap_ip_str);
287 httpd_resp_set_hdr(req, "Location", location); 287 httpd_resp_set_hdr(req, "Location", location);
288 httpd_resp_set_hdr(req, "Connection", "close"); 288 httpd_resp_set_hdr(req, "Connection", "close");
289 httpd_resp_send(req, NULL, 0); 289 httpd_resp_send(req, NULL, 0);
290 return ESP_OK; 290 return ESP_OK;
291 }
292 return ESP_FAIL;
291} 293}
292 294
293static const httpd_uri_t uri_portal = { .uri = "/", .method = HTTP_GET, .handler = portal_handler }; 295static const httpd_uri_t uri_portal = { .uri = "/", .method = HTTP_GET, .handler = portal_handler };
@@ -303,7 +305,6 @@ static const httpd_uri_t uri_success = { .uri = "/success.txt", .method = HTTP_G
303static const httpd_uri_t uri_ncsi = { .uri = "/ncsi.txt", .method = HTTP_GET, .handler = redirect_to_portal_handler }; 305static const httpd_uri_t uri_ncsi = { .uri = "/ncsi.txt", .method = HTTP_GET, .handler = redirect_to_portal_handler };
304static const httpd_uri_t uri_connecttest = { .uri = "/connecttest.txt", .method = HTTP_GET, .handler = redirect_to_portal_handler }; 306static const httpd_uri_t uri_connecttest = { .uri = "/connecttest.txt", .method = HTTP_GET, .handler = redirect_to_portal_handler };
305static const httpd_uri_t uri_wpad = { .uri = "/wpad.dat", .method = HTTP_GET, .handler = redirect_to_portal_handler }; 307static const httpd_uri_t uri_wpad = { .uri = "/wpad.dat", .method = HTTP_GET, .handler = redirect_to_portal_handler };
306static const httpd_uri_t uri_catchall = { .uri = "/*", .method = HTTP_GET, .handler = catchall_handler };
307 308
308static const char SETUP_HTML_TEMPLATE[] = \ 309static const char SETUP_HTML_TEMPLATE[] = \
309"<!DOCTYPE html>" 310"<!DOCTYPE html>"
@@ -545,7 +546,7 @@ static esp_err_t wifi_connect_handler(httpd_req_t *req) {
545 int content_len = req->content_len; 546 int content_len = req->content_len;
546 if (content_len <= 0 || content_len > 1024) { 547 if (content_len <= 0 || content_len > 1024) {
547 httpd_resp_set_type(req, "application/json"); 548 httpd_resp_set_type(req, "application/json");
548 httpd_resp_send(req, "{\"ok\":false,\"error\":\"invalid request\"}", 33); 549 httpd_resp_send(req, "{\"ok\":false,\"error\":\"invalid request\"}", HTTPD_RESP_USE_STRLEN);
549 return ESP_OK; 550 return ESP_OK;
550 } 551 }
551 552
@@ -566,7 +567,7 @@ static esp_err_t wifi_connect_handler(httpd_req_t *req) {
566 free(body); 567 free(body);
567 if (!json) { 568 if (!json) {
568 httpd_resp_set_type(req, "application/json"); 569 httpd_resp_set_type(req, "application/json");
569 httpd_resp_send(req, "{\"ok\":false,\"error\":\"invalid JSON\"}", 33); 570 httpd_resp_send(req, "{\"ok\":false,\"error\":\"invalid JSON\"}", HTTPD_RESP_USE_STRLEN);
570 return ESP_OK; 571 return ESP_OK;
571 } 572 }
572 573
@@ -575,7 +576,7 @@ static esp_err_t wifi_connect_handler(httpd_req_t *req) {
575 if (!ssid_item || !cJSON_IsString(ssid_item)) { 576 if (!ssid_item || !cJSON_IsString(ssid_item)) {
576 cJSON_Delete(json); 577 cJSON_Delete(json);
577 httpd_resp_set_type(req, "application/json"); 578 httpd_resp_set_type(req, "application/json");
578 httpd_resp_send(req, "{\"ok\":false,\"error\":\"missing ssid\"}", 32); 579 httpd_resp_send(req, "{\"ok\":false,\"error\":\"missing ssid\"}", HTTPD_RESP_USE_STRLEN);
579 return ESP_OK; 580 return ESP_OK;
580 } 581 }
581 582
@@ -586,7 +587,7 @@ static esp_err_t wifi_connect_handler(httpd_req_t *req) {
586 if (err != ESP_OK) { 587 if (err != ESP_OK) {
587 cJSON_Delete(json); 588 cJSON_Delete(json);
588 httpd_resp_set_type(req, "application/json"); 589 httpd_resp_set_type(req, "application/json");
589 httpd_resp_send(req, "{\"ok\":false,\"error\":\"save failed\"}", 33); 590 httpd_resp_send(req, "{\"ok\":false,\"error\":\"save failed\"}", HTTPD_RESP_USE_STRLEN);
590 return ESP_OK; 591 return ESP_OK;
591 } 592 }
592 593
@@ -600,7 +601,7 @@ static esp_err_t wifi_connect_handler(httpd_req_t *req) {
600 cJSON_Delete(json); 601 cJSON_Delete(json);
601 602
602 httpd_resp_set_type(req, "application/json"); 603 httpd_resp_set_type(req, "application/json");
603 httpd_resp_send(req, "{\"ok\":true}", 10); 604 httpd_resp_send(req, "{\"ok\":true}", HTTPD_RESP_USE_STRLEN);
604 return ESP_OK; 605 return ESP_OK;
605} 606}
606 607
@@ -644,7 +645,6 @@ esp_err_t captive_portal_start(const char *ap_ip_str)
644 645
645 httpd_config_t config = HTTPD_DEFAULT_CONFIG(); 646 httpd_config_t config = HTTPD_DEFAULT_CONFIG();
646 config.max_uri_handlers = 20; 647 config.max_uri_handlers = 20;
647 config.uri_match_fn = httpd_uri_match_wildcard;
648 648
649 esp_err_t ret = httpd_start(&s_server, &config); 649 esp_err_t ret = httpd_start(&s_server, &config);
650 if (ret != ESP_OK) { 650 if (ret != ESP_OK) {
@@ -666,10 +666,14 @@ esp_err_t captive_portal_start(const char *ap_ip_str)
666 httpd_register_uri_handler(s_server, &uri_connecttest); 666 httpd_register_uri_handler(s_server, &uri_connecttest);
667 httpd_register_uri_handler(s_server, &uri_wpad); 667 httpd_register_uri_handler(s_server, &uri_wpad);
668 httpd_register_uri_handler(s_server, &uri_setup); 668 httpd_register_uri_handler(s_server, &uri_setup);
669 httpd_register_uri_handler(s_server, &uri_wifi_scan); 669 ret = httpd_register_uri_handler(s_server, &uri_wifi_scan);
670 httpd_register_uri_handler(s_server, &uri_wifi_connect); 670 ESP_LOGI(TAG, "Registered /wifi/scan: %s", esp_err_to_name(ret));
671 httpd_register_uri_handler(s_server, &uri_wifi_status); 671 ret = httpd_register_uri_handler(s_server, &uri_wifi_connect);
672 httpd_register_uri_handler(s_server, &uri_catchall); 672 ESP_LOGI(TAG, "Registered /wifi/connect: %s", esp_err_to_name(ret));
673 ret = httpd_register_uri_handler(s_server, &uri_wifi_status);
674 ESP_LOGI(TAG, "Registered /wifi/status: %s", esp_err_to_name(ret));
675
676 httpd_register_err_handler(s_server, HTTPD_404_NOT_FOUND, catchall_err_handler);
673 677
674 ESP_LOGI(TAG, "Captive portal started on port 80"); 678 ESP_LOGI(TAG, "Captive portal started on port 80");
675 return ESP_OK; 679 return ESP_OK;
diff --git a/main/tollgate_main.c b/main/tollgate_main.c
index 9960ea5..ec6ffc8 100644
--- a/main/tollgate_main.c
+++ b/main/tollgate_main.c
@@ -37,11 +37,13 @@ static esp_netif_t *s_ap_netif = NULL;
37static int s_retry_count = 0; 37static int s_retry_count = 0;
38static int s_total_retries = 0; 38static int s_total_retries = 0;
39static bool s_services_running = false; 39static bool s_services_running = false;
40static bool s_start_in_error_state = false;
40static SemaphoreHandle_t s_services_mutex = NULL; 41static SemaphoreHandle_t s_services_mutex = NULL;
41static char s_ap_ip_str[16] = "10.0.0.1"; 42static char s_ap_ip_str[16] = "10.0.0.1";
42 43
43static void start_services(void); 44static void start_services(void);
44static void stop_services(void); 45static void stop_services(void);
46static void services_start_task(void *pvParameters);
45 47
46static void wifi_event_handler(void *arg, esp_event_base_t event_base, 48static void wifi_event_handler(void *arg, esp_event_base_t event_base,
47 int32_t event_id, void *event_data) 49 int32_t event_id, void *event_data)
@@ -60,11 +62,15 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base,
60 tollgate_client_on_sta_disconnected(); 62 tollgate_client_on_sta_disconnected();
61 display_notify_wifi_disconnected(); 63 display_notify_wifi_disconnected();
62 if (s_services_running) { 64 if (s_services_running) {
63 stop_services();
64 display_set_state(DISPLAY_ERROR); 65 display_set_state(DISPLAY_ERROR);
65 } 66 }
66 if (s_total_retries >= MAX_TOTAL_RETRIES) { 67 if (s_total_retries >= MAX_TOTAL_RETRIES) {
67 ESP_LOGW(TAG, "All WiFi retries exhausted"); 68 ESP_LOGW(TAG, "All WiFi retries exhausted");
69 if (!s_services_running) {
70 s_start_in_error_state = true;
71 ESP_LOGI(TAG, "Starting services for /setup access (no upstream)");
72 xTaskCreate(services_start_task, "svc_start", 32768, NULL, 5, NULL);
73 }
68 const tollgate_config_t *cfg = tollgate_config_get(); 74 const tollgate_config_t *cfg = tollgate_config_get();
69 char portal_url[128]; 75 char portal_url[128];
70 snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str); 76 snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str);
@@ -86,6 +92,11 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base,
86 esp_wifi_connect(); 92 esp_wifi_connect();
87 } else { 93 } else {
88 ESP_LOGW(TAG, "No more WiFi networks to try"); 94 ESP_LOGW(TAG, "No more WiFi networks to try");
95 if (!s_services_running) {
96 s_start_in_error_state = true;
97 ESP_LOGI(TAG, "Starting services for /setup access (no upstream)");
98 xTaskCreate(services_start_task, "svc_start", 32768, NULL, 5, NULL);
99 }
89 const tollgate_config_t *cfg = tollgate_config_get(); 100 const tollgate_config_t *cfg = tollgate_config_get();
90 char portal_url[128]; 101 char portal_url[128];
91 snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str); 102 snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str);
@@ -143,7 +154,6 @@ static void ip_event_handler(void *arg, esp_event_base_t event_base,
143 } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) { 154 } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) {
144 ESP_LOGW(TAG, "Lost IP address"); 155 ESP_LOGW(TAG, "Lost IP address");
145 xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); 156 xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
146 stop_services();
147 } 157 }
148} 158}
149 159
@@ -202,6 +212,12 @@ static void start_services(void)
202 if (s_services_mutex) xSemaphoreGive(s_services_mutex); 212 if (s_services_mutex) xSemaphoreGive(s_services_mutex);
203 ESP_LOGI(TAG, "=== TollGate services started ==="); 213 ESP_LOGI(TAG, "=== TollGate services started ===");
204 214
215 if (s_start_in_error_state) {
216 s_start_in_error_state = false;
217 ESP_LOGI(TAG, "Services started in error state (no upstream), keeping DISPLAY_ERROR");
218 return;
219 }
220
205 display_set_state(DISPLAY_READY); 221 display_set_state(DISPLAY_READY);
206 char portal_url[128]; 222 char portal_url[128];
207 snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str); 223 snprintf(portal_url, sizeof(portal_url), "http://%s/", cfg->ap_ip_str);