Skip to content

Commit 0398c33

Browse files
authored
Save the post data in a file on the filesystem (#2810)
* Use cross-browser JS for query params in EUS * Update EUS doc to explain how to use parameters * Remove ; in Lua code * Rewrite the endpoint table * Do not use properties as global Lua variables * remove enduser_setup.html.gz * rename folder 'eus' to 'enduser_setup' * Change input type for password to "password" * Replace outdated captive portal screen shot
1 parent bc7ffb3 commit 0398c33

File tree

11 files changed

+547
-297
lines changed

11 files changed

+547
-297
lines changed

app/modules/enduser_setup.c

Lines changed: 212 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ static const char http_html_filename[] = "enduser_setup.html";
9393
static const char http_header_200[] = "HTTP/1.1 200 OK\r\nCache-control:no-cache\r\nConnection:close\r\nContent-Type:text/html\r\n"; /* Note single \r\n here! */
9494
static const char http_header_204[] = "HTTP/1.1 204 No Content\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
9595
static const char http_header_302[] = "HTTP/1.1 302 Moved\r\nLocation: /\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
96+
static const char http_header_302_trying[] = "HTTP/1.1 302 Moved\r\nLocation: /?trying=true\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
9697
static const char http_header_400[] = "HTTP/1.1 400 Bad request\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
9798
static const char http_header_404[] = "HTTP/1.1 404 Not found\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
9899
static const char http_header_405[] = "HTTP/1.1 405 Method Not Allowed\r\nContent-Length:0\r\nConnection:close\r\n\r\n";
@@ -101,8 +102,8 @@ static const char http_header_500[] = "HTTP/1.1 500 Internal Error\r\nContent-Le
101102
static const char http_header_content_len_fmt[] = "Content-length:%5d\r\n\r\n";
102103
static const char http_html_gzip_contentencoding[] = "Content-Encoding: gzip\r\n";
103104

104-
/* Externally defined: static const char http_html_backup[] = ... */
105-
#include "eus/http_html_backup.def"
105+
/* Externally defined: static const char enduser_setup_html_default[] = ... */
106+
#include "enduser_setup/enduser_setup.html.gz.def.h"
106107

107108
typedef struct scan_listener
108109
{
@@ -398,9 +399,9 @@ static err_t close_once_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
398399
/**
399400
* Search String
400401
*
401-
* Search string for first occurance of any char in srch_str.
402+
* Search string for first occurence of any char in srch_str.
402403
*
403-
* @return -1 iff no occurance of char was found.
404+
* @return -1 if no occurence of char was found.
404405
*/
405406
static int enduser_setup_srch_str(const char *str, const char *srch_str)
406407
{
@@ -418,9 +419,9 @@ static int enduser_setup_srch_str(const char *str, const char *srch_str)
418419
/**
419420
* Load HTTP Payload
420421
*
421-
* @return - 0 iff payload loaded successfully
422-
* 1 iff backup html was loaded
423-
* 2 iff out of memory
422+
* @return - 0 if payload loaded successfully
423+
* 1 if default html was loaded
424+
* 2 if out of memory
424425
*/
425426
static int enduser_setup_http_load_payload(void)
426427
{
@@ -466,16 +467,16 @@ static int enduser_setup_http_load_payload(void)
466467

467468
if (!f || err == VFS_RES_ERR || err2 == VFS_RES_ERR)
468469
{
469-
ENDUSER_SETUP_DEBUG("Unable to load file enduser_setup.html, loading backup HTML...");
470+
ENDUSER_SETUP_DEBUG("Unable to load file enduser_setup.html, loading default HTML...");
470471

471-
c_sprintf(cl_hdr, http_header_content_len_fmt, sizeof(http_html_backup));
472+
c_sprintf(cl_hdr, http_header_content_len_fmt, sizeof(enduser_setup_html_default));
472473
cl_len = c_strlen(cl_hdr);
473-
int html_len = LITLEN(http_html_backup);
474+
int html_len = LITLEN(enduser_setup_html_default);
474475

475-
if (http_html_backup[0] == 0x1f && http_html_backup[1] == 0x8b)
476+
if (enduser_setup_html_default[0] == 0x1f && enduser_setup_html_default[1] == 0x8b)
476477
{
477478
ce_len = c_strlen(http_html_gzip_contentencoding);
478-
html_len = http_html_backup_len; /* Defined in eus/http_html_backup.def by xxd -i */
479+
html_len = enduser_setup_html_default_len; /* Defined in enduser_setup/enduser_setup.html.gz.def.h by xxd -i */
479480
ENDUSER_SETUP_DEBUG("Content is gzipped");
480481
}
481482

@@ -499,7 +500,7 @@ static int enduser_setup_http_load_payload(void)
499500

500501
c_memcpy(&(state->http_payload_data[offset]), &(cl_hdr), cl_len);
501502
offset += cl_len;
502-
c_memcpy(&(state->http_payload_data[offset]), &(http_html_backup), sizeof(http_html_backup));
503+
c_memcpy(&(state->http_payload_data[offset]), &(enduser_setup_html_default), sizeof(enduser_setup_html_default));
503504

504505
return 1;
505506
}
@@ -548,7 +549,7 @@ static int enduser_setup_http_load_payload(void)
548549
*
549550
* Parse escaped and form encoded data of request.
550551
*
551-
* @return - return 0 iff the HTTP parameter is decoded into a valid string.
552+
* @return - return 0 if the HTTP parameter is decoded into a valid string.
552553
*/
553554
static int enduser_setup_http_urldecode(char *dst, const char *src, int src_len, int dst_len)
554555
{
@@ -631,13 +632,167 @@ static void do_station_cfg (task_param_t param, uint8_t prio)
631632
luaM_free(lua_getstate(), cnf);
632633
}
633634

635+
/**
636+
* Count the number of occurences of a character in a string
637+
*
638+
* return the number of times the character was encountered in the string
639+
*/
640+
static int count_char_occurence(const char *input, const char char_to_count) {
641+
const char *current = input;
642+
int occur = 0;
643+
while (*current != 0) {
644+
if (*current == char_to_count) occur++;
645+
current++;
646+
}
647+
return occur;
648+
}
649+
650+
/* structure used to store the key/value pairs that we find in a HTTP POST body */
651+
struct keypairs_t {
652+
char **keypairs;
653+
int keypairs_nb;
654+
};
655+
656+
static void enduser_setup_free_keypairs(struct keypairs_t *kp) {
657+
if (kp == NULL) return;
658+
659+
if (kp->keypairs != NULL) {
660+
for (int i = 0; i < kp->keypairs_nb * 2; i++) {
661+
os_free(kp->keypairs[i]);
662+
}
663+
}
664+
os_free(kp->keypairs);
665+
os_free(kp);
666+
}
667+
668+
static struct keypairs_t * enduser_setup_alloc_keypairs(int kp_number ){
669+
struct keypairs_t *kp = os_malloc(sizeof(struct keypairs_t));
670+
os_memset(kp, 0, sizeof(struct keypairs_t));
671+
672+
kp->keypairs = os_malloc(kp_number * 2 * sizeof(char *));
673+
kp->keypairs_nb = kp_number;
674+
return kp;
675+
}
676+
677+
/**
678+
* Parses a form-urlencoded body into a struct keypairs_t, which contains an array of key,values strings and the size of the array.
679+
*/
680+
static struct keypairs_t *enduser_setup_get_keypairs_from_form(char *form_body, int form_length) {
681+
int keypair_nb = count_char_occurence(form_body, '&') + 1;
682+
int equal_nb = count_char_occurence(form_body, '=');
683+
684+
if (keypair_nb == 1 && equal_nb == 0) {
685+
ENDUSER_SETUP_DEBUG("No keypair in form body");
686+
return NULL;
687+
}
688+
689+
struct keypairs_t *kp = enduser_setup_alloc_keypairs(keypair_nb);
690+
691+
int current_idx = 0;
692+
int err;
693+
694+
char *body_copy = os_malloc(form_length+1);
695+
os_bzero(body_copy, form_length+1);
696+
os_memcpy(body_copy, form_body, form_length);
697+
char *tok = strtok(body_copy, "=");
698+
699+
char last_tok = '=';
700+
while (tok) {
701+
size_t len = strlen(tok);
702+
kp->keypairs[current_idx] = os_malloc(len + 1);
703+
err = enduser_setup_http_urldecode(kp->keypairs[current_idx], tok, len, len + 1);
704+
if (err) {
705+
ENDUSER_SETUP_DEBUG("Unable to decode parameter");
706+
enduser_setup_free_keypairs(kp);
707+
os_free(body_copy);
708+
return NULL;
709+
}
710+
711+
current_idx++;
712+
if (current_idx > keypair_nb*2) {
713+
ENDUSER_SETUP_DEBUG("Too many keypairs!");
714+
enduser_setup_free_keypairs(kp);
715+
os_free(body_copy);
716+
return NULL;
717+
}
718+
719+
if (last_tok == '=') {
720+
tok = strtok(NULL, "&"); // now search for the '&'
721+
last_tok='&';
722+
} else {
723+
tok = strtok(NULL, "="); // search for the next '='
724+
last_tok='=';
725+
}
726+
}
727+
os_free(body_copy);
728+
return kp;
729+
}
730+
731+
732+
/**
733+
* This function saves the form data received when the configuration is sent to the ESP into a eus_params.lua file
734+
*/
735+
static int enduser_setup_write_file_with_extra_configuration_data(char *form_body, int form_length) {
736+
ENDUSER_SETUP_DEBUG("enduser: write data from posted form");
737+
ENDUSER_SETUP_DEBUG(form_body);
738+
739+
// We will save the form data into a file in the LUA format: KEY="VALUE", so that configuration data is available for load in the lua code.
740+
// As input, we have a string as such: "key1=value1&key2=value2&key3=value%203" (urlencoded), the number of '&' tells us how many keypairs there are (the count + 1)
741+
742+
struct keypairs_t *kp = enduser_setup_get_keypairs_from_form(form_body, form_length);
743+
if (kp == NULL || kp->keypairs_nb == 0) {
744+
ENDUSER_SETUP_DEBUG("enduser: No extra configuration.");
745+
if (kp != NULL) enduser_setup_free_keypairs(kp);
746+
return 1;
747+
}
748+
749+
// Now that we have the keys and the values, let's save them in a lua file
750+
int p_file = vfs_open("eus_params.lua", "w");
751+
if (p_file == 0)
752+
{
753+
ENDUSER_SETUP_DEBUG("Can't open file in write mode!");
754+
enduser_setup_free_keypairs(kp);
755+
return 1;
756+
}
757+
758+
// write all key pairs as KEY="VALUE"\n into a Lua table, example:
759+
// local p = {}
760+
// p.wifi_ssid="ssid"
761+
// p.wifi_password="password"
762+
// p.device_name="foo-node"
763+
// return p
764+
vfs_write(p_file, "local p={}\n", 11);
765+
int idx = 0;
766+
for( idx = 0; idx < kp->keypairs_nb*2; idx=idx+2){
767+
char* to_write = kp->keypairs[idx];
768+
size_t length = c_strlen(to_write);
769+
770+
vfs_write(p_file, "p.", 2);
771+
772+
vfs_write(p_file, to_write, length);
773+
774+
vfs_write(p_file, "=\"", 2);
775+
776+
to_write = kp->keypairs[idx+1];
777+
length = c_strlen(to_write);
778+
vfs_write(p_file, to_write, length);
779+
780+
vfs_write(p_file, "\"\n", 2);
781+
}
782+
vfs_write(p_file, "return p\n", 9);
783+
784+
vfs_close(p_file);
785+
enduser_setup_free_keypairs(kp);
786+
// TODO: we could call back in the LUA with an associative table setup, but this is MVP2...
787+
return 0;
788+
}
634789

635790
/**
636791
* Handle HTTP Credentials
637792
*
638-
* @return - return 0 iff credentials are found and handled successfully
639-
* return 1 iff credentials aren't found
640-
* return 2 iff an error occured
793+
* @return - return 0 if credentials are found and handled successfully
794+
* return 1 if credentials aren't found
795+
* return 2 if an error occured
641796
*/
642797
static int enduser_setup_http_handle_credentials(char *data, unsigned short data_len)
643798
{
@@ -682,7 +837,6 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
682837
return 1;
683838
}
684839

685-
686840
ENDUSER_SETUP_DEBUG("");
687841
ENDUSER_SETUP_DEBUG("WiFi Credentials Stored");
688842
ENDUSER_SETUP_DEBUG("-----------------------");
@@ -702,7 +856,7 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
702856
/**
703857
* Serve HTML
704858
*
705-
* @return - return 0 iff html was served successfully
859+
* @return - return 0 if html was served successfully
706860
*/
707861
static int enduser_setup_http_serve_header(struct tcp_pcb *http_client, const char *header, uint32_t header_len)
708862
{
@@ -763,7 +917,7 @@ static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
763917
/**
764918
* Serve HTML
765919
*
766-
* @return - return 0 iff html was served successfully
920+
* @return - return 0 if html was served successfully
767921
*/
768922
static int enduser_setup_http_serve_html(struct tcp_pcb *http_client)
769923
{
@@ -957,6 +1111,37 @@ static void enduser_setup_handle_OPTIONS (struct tcp_pcb *http_client, char *dat
9571111
}
9581112

9591113

1114+
static err_t enduser_setup_handle_POST(struct tcp_pcb *http_client, char* data, size_t data_len)
1115+
{
1116+
ENDUSER_SETUP_DEBUG("Handling POST");
1117+
if (c_strncmp(data + 5, "/setwifi ", 9) == 0) // User clicked the submit button
1118+
{
1119+
switch (enduser_setup_http_handle_credentials(data, data_len))
1120+
{
1121+
case 0: {
1122+
// all went fine, extract all the form data into a file
1123+
char* body=strstr(data, "\r\n\r\n");
1124+
char *content_length_str = strstr(data, "Content-Length: ");
1125+
if( body != NULL && content_length_str != NULL){
1126+
int bodylength = c_atoi(content_length_str + 16);
1127+
body += 4; // length of the double CRLF found above
1128+
enduser_setup_write_file_with_extra_configuration_data(body, bodylength);
1129+
}
1130+
// redirect user to the base page with the trying flag
1131+
enduser_setup_http_serve_header(http_client, http_header_302_trying, LITLEN(http_header_302_trying));
1132+
break;
1133+
}
1134+
case 1:
1135+
enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400));
1136+
break;
1137+
default:
1138+
ENDUSER_SETUP_ERROR("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
1139+
break;
1140+
}
1141+
}
1142+
}
1143+
1144+
9601145
/* --- WiFi AP scanning support -------------------------------------------- */
9611146

9621147
static void free_scan_listeners (void)
@@ -1165,7 +1350,7 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
11651350

11661351
if (c_strncmp(data, "GET ", 4) == 0)
11671352
{
1168-
if (c_strncmp(data + 4, "/ ", 2) == 0)
1353+
if (c_strncmp(data + 4, "/ ", 2) == 0 || c_strncmp(data + 4, "/?", 2) == 0)
11691354
{
11701355
if (enduser_setup_http_serve_html(http_client) != 0)
11711356
{
@@ -1237,21 +1422,6 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
12371422
break;
12381423
}
12391424
}
1240-
else if (c_strncmp(data + 4, "/setwifi?", 9) == 0)
1241-
{
1242-
switch (enduser_setup_http_handle_credentials(data, data_len))
1243-
{
1244-
case 0:
1245-
enduser_setup_serve_status_as_json(http_client);
1246-
break;
1247-
case 1:
1248-
enduser_setup_http_serve_header(http_client, http_header_400, LITLEN(http_header_400));
1249-
break;
1250-
default:
1251-
ENDUSER_SETUP_ERROR("http_recvcb failed. Failed to handle wifi credentials.", ENDUSER_SETUP_ERR_UNKOWN_ERROR, ENDUSER_SETUP_ERR_NONFATAL);
1252-
break;
1253-
}
1254-
}
12551425
else if (c_strncmp(data + 4, "/generate_204", 13) == 0)
12561426
{
12571427
/* Convince Android devices that they have internet access to avoid pesky dialogues. */
@@ -1267,6 +1437,10 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
12671437
{
12681438
enduser_setup_handle_OPTIONS(http_client, data, data_len);
12691439
}
1440+
else if (c_strncmp(data, "POST ", 5) == 0)
1441+
{
1442+
enduser_setup_handle_POST(http_client, data, data_len);
1443+
}
12701444
else /* not GET or OPTIONS */
12711445
{
12721446
enduser_setup_http_serve_header(http_client, http_header_405, LITLEN(http_header_405));
@@ -1279,6 +1453,7 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
12791453
return ret;
12801454
}
12811455

1456+
12821457
static err_t enduser_setup_http_connectcb(void *arg, struct tcp_pcb *pcb, err_t err)
12831458
{
12841459
ENDUSER_SETUP_DEBUG("enduser_setup_http_connectcb");
@@ -1332,7 +1507,7 @@ static int enduser_setup_http_start(void)
13321507
int err = enduser_setup_http_load_payload();
13331508
if (err == 1)
13341509
{
1335-
ENDUSER_SETUP_DEBUG("enduser_setup_http_start info. Loaded backup HTML.");
1510+
ENDUSER_SETUP_DEBUG("enduser_setup_http_start info. Loaded default HTML.");
13361511
}
13371512
else if (err == 2)
13381513
{
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.sh text eol=lf

app/modules/enduser_setup/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enduser_setup.html.gz

0 commit comments

Comments
 (0)