@@ -93,6 +93,7 @@ static const char http_html_filename[] = "enduser_setup.html";
93
93
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! */
94
94
static const char http_header_204 [] = "HTTP/1.1 204 No Content\r\nContent-Length:0\r\nConnection:close\r\n\r\n" ;
95
95
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" ;
96
97
static const char http_header_400 [] = "HTTP/1.1 400 Bad request\r\nContent-Length:0\r\nConnection:close\r\n\r\n" ;
97
98
static const char http_header_404 [] = "HTTP/1.1 404 Not found\r\nContent-Length:0\r\nConnection:close\r\n\r\n" ;
98
99
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
101
102
static const char http_header_content_len_fmt [] = "Content-length:%5d\r\n\r\n" ;
102
103
static const char http_html_gzip_contentencoding [] = "Content-Encoding: gzip\r\n" ;
103
104
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 "
106
107
107
108
typedef struct scan_listener
108
109
{
@@ -398,9 +399,9 @@ static err_t close_once_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
398
399
/**
399
400
* Search String
400
401
*
401
- * Search string for first occurance of any char in srch_str.
402
+ * Search string for first occurence of any char in srch_str.
402
403
*
403
- * @return -1 iff no occurance of char was found.
404
+ * @return -1 if no occurence of char was found.
404
405
*/
405
406
static int enduser_setup_srch_str (const char * str , const char * srch_str )
406
407
{
@@ -418,9 +419,9 @@ static int enduser_setup_srch_str(const char *str, const char *srch_str)
418
419
/**
419
420
* Load HTTP Payload
420
421
*
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
424
425
*/
425
426
static int enduser_setup_http_load_payload (void )
426
427
{
@@ -466,16 +467,16 @@ static int enduser_setup_http_load_payload(void)
466
467
467
468
if (!f || err == VFS_RES_ERR || err2 == VFS_RES_ERR )
468
469
{
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..." );
470
471
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 ));
472
473
cl_len = c_strlen (cl_hdr );
473
- int html_len = LITLEN (http_html_backup );
474
+ int html_len = LITLEN (enduser_setup_html_default );
474
475
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 )
476
477
{
477
478
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 */
479
480
ENDUSER_SETUP_DEBUG ("Content is gzipped" );
480
481
}
481
482
@@ -499,7 +500,7 @@ static int enduser_setup_http_load_payload(void)
499
500
500
501
c_memcpy (& (state -> http_payload_data [offset ]), & (cl_hdr ), cl_len );
501
502
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 ));
503
504
504
505
return 1 ;
505
506
}
@@ -548,7 +549,7 @@ static int enduser_setup_http_load_payload(void)
548
549
*
549
550
* Parse escaped and form encoded data of request.
550
551
*
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.
552
553
*/
553
554
static int enduser_setup_http_urldecode (char * dst , const char * src , int src_len , int dst_len )
554
555
{
@@ -631,13 +632,167 @@ static void do_station_cfg (task_param_t param, uint8_t prio)
631
632
luaM_free (lua_getstate (), cnf );
632
633
}
633
634
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
+ }
634
789
635
790
/**
636
791
* Handle HTTP Credentials
637
792
*
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
641
796
*/
642
797
static int enduser_setup_http_handle_credentials (char * data , unsigned short data_len )
643
798
{
@@ -682,7 +837,6 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
682
837
return 1 ;
683
838
}
684
839
685
-
686
840
ENDUSER_SETUP_DEBUG ("" );
687
841
ENDUSER_SETUP_DEBUG ("WiFi Credentials Stored" );
688
842
ENDUSER_SETUP_DEBUG ("-----------------------" );
@@ -702,7 +856,7 @@ static int enduser_setup_http_handle_credentials(char *data, unsigned short data
702
856
/**
703
857
* Serve HTML
704
858
*
705
- * @return - return 0 iff html was served successfully
859
+ * @return - return 0 if html was served successfully
706
860
*/
707
861
static int enduser_setup_http_serve_header (struct tcp_pcb * http_client , const char * header , uint32_t header_len )
708
862
{
@@ -763,7 +917,7 @@ static err_t streamout_sent (void *arg, struct tcp_pcb *pcb, u16_t len)
763
917
/**
764
918
* Serve HTML
765
919
*
766
- * @return - return 0 iff html was served successfully
920
+ * @return - return 0 if html was served successfully
767
921
*/
768
922
static int enduser_setup_http_serve_html (struct tcp_pcb * http_client )
769
923
{
@@ -957,6 +1111,37 @@ static void enduser_setup_handle_OPTIONS (struct tcp_pcb *http_client, char *dat
957
1111
}
958
1112
959
1113
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
+
960
1145
/* --- WiFi AP scanning support -------------------------------------------- */
961
1146
962
1147
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
1165
1350
1166
1351
if (c_strncmp (data , "GET " , 4 ) == 0 )
1167
1352
{
1168
- if (c_strncmp (data + 4 , "/ " , 2 ) == 0 )
1353
+ if (c_strncmp (data + 4 , "/ " , 2 ) == 0 || c_strncmp ( data + 4 , "/?" , 2 ) == 0 )
1169
1354
{
1170
1355
if (enduser_setup_http_serve_html (http_client ) != 0 )
1171
1356
{
@@ -1237,21 +1422,6 @@ static err_t enduser_setup_http_recvcb(void *arg, struct tcp_pcb *http_client, s
1237
1422
break ;
1238
1423
}
1239
1424
}
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
- }
1255
1425
else if (c_strncmp (data + 4 , "/generate_204" , 13 ) == 0 )
1256
1426
{
1257
1427
/* 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
1267
1437
{
1268
1438
enduser_setup_handle_OPTIONS (http_client , data , data_len );
1269
1439
}
1440
+ else if (c_strncmp (data , "POST " , 5 ) == 0 )
1441
+ {
1442
+ enduser_setup_handle_POST (http_client , data , data_len );
1443
+ }
1270
1444
else /* not GET or OPTIONS */
1271
1445
{
1272
1446
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
1279
1453
return ret ;
1280
1454
}
1281
1455
1456
+
1282
1457
static err_t enduser_setup_http_connectcb (void * arg , struct tcp_pcb * pcb , err_t err )
1283
1458
{
1284
1459
ENDUSER_SETUP_DEBUG ("enduser_setup_http_connectcb" );
@@ -1332,7 +1507,7 @@ static int enduser_setup_http_start(void)
1332
1507
int err = enduser_setup_http_load_payload ();
1333
1508
if (err == 1 )
1334
1509
{
1335
- ENDUSER_SETUP_DEBUG ("enduser_setup_http_start info. Loaded backup HTML." );
1510
+ ENDUSER_SETUP_DEBUG ("enduser_setup_http_start info. Loaded default HTML." );
1336
1511
}
1337
1512
else if (err == 2 )
1338
1513
{
0 commit comments