Browse Source

WIP httpd - saving current work. likely won't compile right now!

Sebastien 5 years ago
parent
commit
87255733a5

+ 5 - 4
components/cmd_i2c/CMakeLists.txt

@@ -1,5 +1,6 @@
-set(COMPONENT_SRCS "cmd_i2ctools.c")
-set(COMPONENT_ADD_INCLUDEDIRS ".")
-set(COMPONENT_REQUIRES console spi_flash)
+idf_component_register(SRCS "cmd_i2ctools.c"
+                       INCLUDE_DIRS "." "../tools/"
+                       REQUIRES esp_common
+                       PRIV_REQUIRES freertos esp32 spi_flash newlib log console pthread
+)
 
-register_component()

+ 6 - 1
components/cmd_i2c/component.mk

@@ -1,4 +1,9 @@
 #
 # Main Makefile. This is basically the same as a component makefile.
 #
-COMPONENT_ADD_INCLUDEDIRS := .
+CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \
+	-I$(COMPONENT_PATH)/../tools				
+COMPONENT_ADD_INCLUDEDIRS := .
+COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools
+COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../squeezelite-ota
+COMPONENT_EXTRA_INCLUDES += $(PROJECT_PATH)/main/

+ 81 - 22
components/wifi-manager/code.js

@@ -10,6 +10,19 @@ if (!String.prototype.format) {
         });
     };
 }
+var nvs_type_t = {
+    NVS_TYPE_U8    : 0x01,  /*!< Type uint8_t */
+    NVS_TYPE_I8    : 0x11,  /*!< Type int8_t */
+    NVS_TYPE_U16   : 0x02,  /*!< Type uint16_t */
+    NVS_TYPE_I16   : 0x12,  /*!< Type int16_t */
+    NVS_TYPE_U32   : 0x04,  /*!< Type uint32_t */
+    NVS_TYPE_I32   : 0x14,  /*!< Type int32_t */
+    NVS_TYPE_U64   : 0x08,  /*!< Type uint64_t */
+    NVS_TYPE_I64   : 0x18,  /*!< Type int64_t */
+    NVS_TYPE_STR   : 0x21,  /*!< Type string */
+    NVS_TYPE_BLOB  : 0x42,  /*!< Type blob */
+    NVS_TYPE_ANY   : 0xff   /*!< Must be last */
+} ;
 
 var releaseURL = 'https://api.github.com/repos/sle118/squeezelite-esp32/releases';
 var recovery = false;
@@ -189,16 +202,25 @@ $(document).ready(function(){
     $("input#autoexec-cb").on("click", function() {
         var data = { 'timestamp': Date.now() };
         autoexec = (this.checked)?1:0;
-        data['autoexec'] = autoexec;
+        data['config'] = {};
+        data['config'] = {
+            autoexec : {
+                value : autoexec,
+                type : 33
+            }
+        }
+
+
         showMessage('please wait for the ESP32 to reboot', 'WARNING');
         $.ajax({
             url: '/config.json',
             dataType: 'text',
             method: 'POST',
             cache: false,
-            headers: { "X-Custom-autoexec": autoexec },
+//            headers: { "X-Custom-autoexec": autoexec },
             contentType: 'application/json; charset=utf-8',
-            data: JSON.stringify(data),
+            data:  JSON.stringify(data),
+
             error: function (xhr, ajaxOptions, thrownError) {
                 console.log(xhr.status);
                 console.log(thrownError);
@@ -232,14 +254,20 @@ $(document).ready(function(){
     $("input#save-autoexec1").on("click", function() {
         var data = { 'timestamp': Date.now() };
         autoexec1 = $("#autoexec1").val();
-        data['autoexec1'] = autoexec1;
+        data['config'] = {};
+        data['config'] = {
+            autoexec1 : {
+                value : autoexec1,
+                type : 33
+            }
+        }
 
         $.ajax({
             url: '/config.json',
             dataType: 'text',
             method: 'POST',
             cache: false,
-            headers: { "X-Custom-autoexec1": autoexec1 },
+//            headers: { "X-Custom-autoexec1": autoexec1 },
             contentType: 'application/json; charset=utf-8',
             data: JSON.stringify(data),
             error: function (xhr, ajaxOptions, thrownError) {
@@ -254,15 +282,19 @@ $(document).ready(function(){
 
     $("input#save-gpio").on("click", function() {
         var data = { 'timestamp': Date.now() };
+        var config = {};
+
         var headers = {};
         $("input.gpio").each(function() {
             var id = $(this)[0].id;
             var pin = $(this).val();
             if (pin != '') {
-                headers["X-Custom-"+id] = pin;
-                data[id] = pin;
+                config[id] = {};
+                config[id].value = pin;
+                config[id].type = nvs_type_t.NVS_TYPE_STR;
             }
         });
+        data['config'] = config;
         $.ajax({
             url: '/config.json',
             dataType: 'text',
@@ -284,23 +316,40 @@ $(document).ready(function(){
     $("#save-nvs").on("click", function() {
         var headers = {};
         var data = { 'timestamp': Date.now() };
+        var config = {};
         $("input.nvs").each(function() {
             var key = $(this)[0].id;
             var val = $(this).val();
+            var nvs_type = parseInt($(this)[0].attributes.nvs_type.nodeValue,10);
             if (key != '') {
-                headers["X-Custom-"+key] = val;
-                data[key] = {};
-                data[key].value = val;
-                data[key].type = 33;
+                config[key] = {};
+                if(nvs_type == nvs_type_t.NVS_TYPE_U8    
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_I8    
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_U16   
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_I16   
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_U32   
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_I32   
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_U64   
+					|| nvs_type ==  nvs_type_t.NVS_TYPE_I64) {
+						config[key].value = parseInt(val);	
+				}   
+				else { 
+					config[key].value = val; 
+				} 
+                
+                
+                config[key].type = nvs_type;
             }
         });
         var key = $("#nvs-new-key").val();
         var val = $("#nvs-new-value").val();
         if (key != '') {
-            headers["X-Custom-"+key] = val;
-            data[key] = {};
-            data[key].value = val;
+//            headers["X-Custom-"	+key] = val;
+            config[key] = {};
+            config[key].value = val;
+            config[key].type = 33;
         }
+        data['config'] = config;
         $.ajax({
             url: '/config.json',
             dataType: 'text',
@@ -308,7 +357,7 @@ $(document).ready(function(){
             cache: false,
             headers: headers,
             contentType: 'application/json; charset=utf-8',
-            data: JSON.stringify(data),
+            data : JSON.stringify(data),
             error: function (xhr, ajaxOptions, thrownError) {
                 console.log(xhr.status);
                 console.log(thrownError);
@@ -324,15 +373,21 @@ $(document).ready(function(){
         if (blockFlashButton) return;
         blockFlashButton = true;
         var url = $("#fwurl").val();
-        data['fwurl'] = url;
+        data['config'] = {
+            fwurl : {
+            value : url,
+            type : 33
+
+            }
+        };
+
         $.ajax({
             url: '/config.json',
             dataType: 'text',
             method: 'POST',
             cache: false,
-            headers: { "X-Custom-fwurl": url },
             contentType: 'application/json; charset=utf-8',
-            data: JSON.stringify(data),
+            data:  JSON.stringify(data),
             error: function (xhr, ajaxOptions, thrownError) {
                 console.log(xhr.status);
                 console.log(thrownError);
@@ -509,9 +564,13 @@ function performConnect(conntype){
         dataType: 'text',
         method: 'POST',
         cache: false,
-        headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd, 'X-Custom-host_name': dhcpname },
+//        headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd, 'X-Custom-host_name': dhcpname },
         contentType: 'application/json; charset=utf-8',
-        data: { 'timestamp': Date.now()},
+        data: JSON.stringify({ 'timestamp': Date.now(),
+        	'ssid' : selectedSSID, 
+        	'pwd' : pwd,
+        	'host_name' : dhcpname
+        	}), 
         error: function (xhr, ajaxOptions, thrownError) {
             console.log(xhr.status);
             console.log(thrownError);
@@ -737,7 +796,7 @@ function getConfig() {
                     "<tr>"+
                         "<td>"+key+"</td>"+
                         "<td class='value'>"+
-                            "<input type='text' class='form-control nvs' id='"+key+"'>"+
+                            "<input type='text' class='form-control nvs' id='"+key+"'  nvs_type="+data[key].type+" >"+
                         "</td>"+
                     "</tr>"
                 );
@@ -750,7 +809,7 @@ function getConfig() {
                     "<input type='text' class='form-control' id='nvs-new-key' placeholder='new key'>"+
                 "</td>"+
                 "<td>"+
-                    "<input type='text' class='form-control' id='nvs-new-value' placeholder='new value'>"+
+                    "<input type='text' class='form-control' id='nvs-new-value' placeholder='new value' nvs_type=33 >"+ // todo: provide a way to choose field type 
                 "</td>"+
             "</tr>"
         );

+ 2 - 2
components/wifi-manager/component.mk

@@ -8,8 +8,8 @@
 #
 COMPONENT_EMBED_FILES := style.css code.js index.html bootstrap.min.css.gz jquery.min.js.gz popper.min.js.gz bootstrap.min.js.gz
 #CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG 
-CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_INFO \
-	-I$(COMPONENT_PATH)/../tools				
+CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG \
+	-I$(COMPONENT_PATH)/../tools			
 COMPONENT_ADD_INCLUDEDIRS := .
 COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../tools
 COMPONENT_ADD_INCLUDEDIRS += $(COMPONENT_PATH)/../squeezelite-ota

+ 479 - 262
components/wifi-manager/http_server_handlers.c

@@ -45,30 +45,39 @@ function to process requests, decode URLs, serve files, etc. etc.
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "config.h"
+#include "sys/param.h"
+#include "esp_vfs.h"
+#include "lwip/ip_addr.h"
 
 #define HTTP_STACK_SIZE	(5*1024)
 #define FREE_AND_NULL(p) if(p!=NULL){ free(p); p=NULL;}
-
+const char str_na[]="N/A";
+#define STR_OR_NA(s) s?s:str_na
 /* @brief tag used for ESP serial console messages */
 static const char TAG[] = "http_server";
 /* @brief task handle for the http server */
-static TaskHandle_t task_http_server = NULL;
-static StaticTask_t task_http_buffer;
-#if RECOVERY_APPLICATION
-static StackType_t task_http_stack[HTTP_STACK_SIZE];
-#else
-static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE];
-#endif
+
 SemaphoreHandle_t http_server_config_mutex = NULL;
 
 #define AUTH_TOKEN_SIZE 50
 typedef struct session_context {
     char * auth_token;
     bool authenticated;
+    char * sess_ip_address;
+    u16_t port;
 } session_context_t;
 
 
+union sockaddr_aligned {
+	struct sockaddr     sa;
+    struct sockaddr_storage st;
+    struct sockaddr_in  sin;
+    struct sockaddr_in6 sin6;
+} aligned_sockaddr_t;
 
+static const char redirect_payload1[]="<html><head><title>Redirecting to Captive Portal</title><meta http-equiv='refresh' content='0; url=";
+static const char redirect_payload2[]="'></head><body><p>Please wait, refreshing.  If page does not refresh, click <a href='";
+static const char redirect_payload3[]="'>here</a> to login.</p></body></html>";
 
 /**
  * @brief embedded binary data.
@@ -103,40 +112,117 @@ extern const uint8_t index_html_end[] asm("_binary_index_html_end");
 //const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://";
 //const static char http_redirect_hdr_end[] = "/\n\n";
 
+char * alloc_get_http_header(httpd_req_t * req, const char * key){
+    char*  buf = NULL;
+    size_t buf_len;
+
+    /* Get header value string length and allocate memory for length + 1,
+     * extra byte for null termination */
+    buf_len = httpd_req_get_hdr_value_len(req, key) + 1;
+    if (buf_len > 1) {
+        buf = malloc(buf_len);
+        /* Copy null terminated value string into buffer */
+        if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) {
+            ESP_LOGD_LOC(TAG, "Found header => %s: %s",key, buf);
+        }
+    }
+    return buf;
+}
+
+
+char * http_alloc_get_socket_address(httpd_req_t *req, u8_t local, in_port_t * portl) {
+
+	socklen_t len;
+	union sockaddr_aligned addr;
+	len = sizeof(addr);
+	ip_addr_t * ip_addr=NULL;
+	char * ipstr = malloc(INET6_ADDRSTRLEN);
+	memset(ipstr,0x0,INET6_ADDRSTRLEN);
+
+	typedef int (*getaddrname_fn_t)(int s, struct sockaddr *name, socklen_t *namelen);
+	getaddrname_fn_t get_addr = NULL;
+
+	int s = httpd_req_to_sockfd(req);
+	if(s == -1) {
+		return strdup("httpd_req_to_sockfd error");
+	}
+	ESP_LOGV_LOC(TAG,"httpd socket descriptor: %u", s);
+
+	get_addr = local?&lwip_getsockname:&lwip_getpeername;
+	if(get_addr(s, (struct sockaddr *)&addr, &len) <0){
+		ESP_LOGE_LOC(TAG,"Failed to retrieve socket address");
+		sprintf(ipstr,"N/A (0.0.0.%u)",local);
+	}
+	else {
+		if (addr.sin.sin_family!= AF_INET) {
+			ip_addr = (ip_addr_t *)&(addr.sin6.sin6_addr);
+			inet_ntop(addr.sa.sa_family, ip_addr, ipstr, INET6_ADDRSTRLEN);
+			ESP_LOGV_LOC(TAG,"Processing an IPV6 address : %s", ipstr);
+			*portl =  addr.sin6.sin6_port;
+			unmap_ipv4_mapped_ipv6(ip_2_ip4(ip_addr), ip_2_ip6(ip_addr));
+		}
+		else {
+			ip_addr = (ip_addr_t *)&(addr.sin.sin_addr);
+			inet_ntop(addr.sa.sa_family, ip_addr, ipstr, INET6_ADDRSTRLEN);
+			ESP_LOGV_LOC(TAG,"Processing an IPV6 address : %s", ipstr);
+			*portl =  addr.sin.sin_port;
+		}
+		inet_ntop(AF_INET, ip_addr, ipstr, INET6_ADDRSTRLEN);
+		ESP_LOGV_LOC(TAG,"Retrieved ip address:port = %s:%u",ipstr, *portl);
+	}
+	return ipstr;
+}
+
 
 /* Custom function to free context */
 void free_ctx_func(void *ctx)
 {
-    if(ctx){
-    	if(ctx->auth_token) free(auth_token);
-    	free(ctx);
+	session_context_t * context = (session_context_t *)ctx;
+    if(context){
+    	FREE_AND_NULL(context->auth_token);
+    	FREE_AND_NULL(context->sess_ip_address);
+    	free(context);
     }
 }
 
+session_context_t* get_session_context(httpd_req_t *req){
+	if (! req->sess_ctx) {
+		req->sess_ctx = malloc(sizeof(session_context_t));
+		memset(req->sess_ctx,0x00,sizeof(session_context_t));
+		req->free_ctx = free_ctx_func;
+		// get the remote IP address only once per session
+	}
+	session_context_t *ctx_data = (session_context_t*)req->sess_ctx;
+	ctx_data->sess_ip_address = http_alloc_get_socket_address(req, 0, &ctx_data->port);
+	ESP_LOGI_LOC(TAG, "serving %s to peer %s port %u", req->uri, ctx_data->sess_ip_address , ctx_data->port);
+	return (session_context_t *)req->sess_ctx;
+}
+
 bool is_user_authenticated(httpd_req_t *req){
-	    if (! req->sess_ctx) {
-	        req->sess_ctx = malloc(sizeof(session_context_t));
-	        memset(req->sess_ctx,0x00,sizeof(session_context_t));
-	        req->free_ctx = free_ctx_func;
-	    }
-	    session_context_t *ctx_data = (session_context_t*)req->sess_ctx;
-	    if(ctx_data->authenticated){
-	    	ESP_LOGD(TAG,"User is authenticated.");
-	    	return true;
-	    }
-
-	    // todo:  ask for user to authenticate
-	    return false;
+	session_context_t *ctx_data = get_session_context(req);
+	if(ctx_data->authenticated){
+		ESP_LOGD_LOC(TAG,"User is authenticated.");
+		return true;
+	}
+
+	ESP_LOGD(TAG,"Heap internal:%zu (min:%zu) external:%zu (min:%zu)",
+				heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
+				heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
+				heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
+				heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
+
+	// todo:  ask for user to authenticate
+	return false;
 }
 
 
 
 /* Copies the full path into destination buffer and returns
- * pointer to path (skipping the preceding base path) */
-static const char* get_path_from_uri(char *dest, const char *base_path, const char *uri, size_t destsize)
+ * pointer to requested file name */
+static const char* get_path_from_uri(char *dest, const char *uri, size_t destsize)
 {
-    const size_t base_pathlen = strlen(base_path);
     size_t pathlen = strlen(uri);
+    memset(dest,0x0,destsize);
 
     const char *quest = strchr(uri, '?');
     if (quest) {
@@ -147,17 +233,29 @@ static const char* get_path_from_uri(char *dest, const char *base_path, const ch
         pathlen = MIN(pathlen, hash - uri);
     }
 
-    if (base_pathlen + pathlen + 1 > destsize) {
+    if ( pathlen + 1 > destsize) {
         /* Full path string won't fit into destination buffer */
         return NULL;
     }
 
-    /* Construct full path (base + path) */
-    strcpy(dest, base_path);
-    strlcpy(dest + base_pathlen, uri, pathlen + 1);
+    strlcpy(dest , uri, pathlen + 1);
+
+    // strip trailing blanks
+    char * sr = dest+pathlen;
+    while(*sr== ' ') *sr-- = '\0';
+
+    char * last_fs = strchr(dest,'/');
+    if(!last_fs) ESP_LOGD_LOC(TAG,"no / found in %s", dest);
+    char * p=last_fs;
+    while(p && *(++p)!='\0'){
+    	if(*p == '/') {
+    		last_fs=p;
+    	}
+    }
+
 
     /* Return pointer to path, skipping the base */
-    return dest + base_pathlen;
+    return last_fs? ++last_fs: dest;
 }
 
 #define IS_FILE_EXT(filename, ext) \
@@ -169,7 +267,7 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena
     if (IS_FILE_EXT(filename, ".pdf")) {
         return httpd_resp_set_type(req, "application/pdf");
     } else if (IS_FILE_EXT(filename, ".html")) {
-        return httpd_resp_set_type(req, "text/html");
+        return httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
     } else if (IS_FILE_EXT(filename, ".jpeg")) {
         return httpd_resp_set_type(req, "image/jpeg");
     } else if (IS_FILE_EXT(filename, ".ico")) {
@@ -181,7 +279,7 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena
     } else if (IS_FILE_EXT(filename, ".js")) {
         return httpd_resp_set_type(req, "text/javascript");
     } else if (IS_FILE_EXT(filename, ".json")) {
-        return httpd_resp_set_type(req, "application/json");
+        return httpd_resp_set_type(req, HTTPD_TYPE_JSON);
     }
     /* This is a limited set only */
     /* For any other type always set as plain text */
@@ -190,17 +288,16 @@ static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filena
 static esp_err_t set_content_type_from_req(httpd_req_t *req)
 {
 	char filepath[FILE_PATH_MAX];
-	const char *filename = get_path_from_uri(filepath, "/" ,
-										req->uri, sizeof(filepath));
+	const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath));
    if (!filename) {
-	   ESP_LOGE(TAG, "Filename is too long");
+	   ESP_LOGE_LOC(TAG, "Filename is too long");
 	   /* Respond with 500 Internal Server Error */
 	   httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
 	   return ESP_FAIL;
    }
 
    /* If name has trailing '/', respond with directory contents */
-   if (filename[strlen(filename) - 1] == '/') {
+   if (filename[strlen(filename) - 1] == '/' && strlen(filename)>1) {
 	   httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Browsing files forbidden.");
 	   return ESP_FAIL;
    }
@@ -209,11 +306,11 @@ static esp_err_t set_content_type_from_req(httpd_req_t *req)
 
 
 esp_err_t root_get_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
     httpd_resp_set_hdr(req, "Accept-Encoding", "identity");
 
-    if(!is_user_authenticated(httpd_req_t *req)){
+    if(!is_user_authenticated(req)){
     	// todo:  send password entry page and return
     }
     const size_t file_size = (index_html_end - index_html_start);
@@ -226,13 +323,12 @@ esp_err_t root_get_handler(httpd_req_t *req){
 
 esp_err_t resource_filehandler(httpd_req_t *req){
     char filepath[FILE_PATH_MAX];
-   ESP_LOGI(TAG, "serving [%s]", req->uri);
+   ESP_LOGI_LOC(TAG, "serving [%s]", req->uri);
 
-   const char *filename = get_path_from_uri(filepath, "/res/" ,
-											req->uri, sizeof(filepath));
+   const char *filename = get_path_from_uri(filepath, req->uri, sizeof(filepath));
 
    if (!filename) {
-	   ESP_LOGE(TAG, "Filename is too long");
+	   ESP_LOGE_LOC(TAG, "Filename is too long");
 	   /* Respond with 500 Internal Server Error */
 	   httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
 	   return ESP_FAIL;
@@ -244,92 +340,92 @@ esp_err_t resource_filehandler(httpd_req_t *req){
 	   return ESP_FAIL;
    }
 
-   if(strstr(line, "GET /code.js ")) {
+   if(strstr(filename, "code.js")) {
 	    const size_t file_size = (code_js_end - code_js_start);
 	    set_content_type_from_file(req, filename);
 	    httpd_resp_send(req, (const char *)code_js_start, file_size);
 	}
-	else if(strstr(line, "GET /style.css ")) {
+	else if(strstr(filename, "style.css")) {
 		set_content_type_from_file(req, filename);
 	    const size_t file_size = (style_css_end - style_css_start);
 	    httpd_resp_send(req, (const char *)style_css_start, file_size);
-	} else if(strstr(line, "GET /jquery.js ")) {
+	} else if(strstr(filename, "jquery.js")) {
 		set_content_type_from_file(req, filename);
 		httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
 	    const size_t file_size = (jquery_gz_end - jquery_gz_start);
 	    httpd_resp_send(req, (const char *)jquery_gz_start, file_size);
-	}else if(strstr(line, "GET /popper.js")) {
+	}else if(strstr(filename, "popper.js")) {
 		set_content_type_from_file(req, filename);
 		httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
 	    const size_t file_size = (popper_gz_end - popper_gz_start);
 	    httpd_resp_send(req, (const char *)popper_gz_start, file_size);
 	}
-	else if(strstr(line, "GET /bootstrap.js ")) {
+	else if(strstr(filename, "bootstrap.js")) {
 			set_content_type_from_file(req, filename);
 			httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
 		    const size_t file_size = (bootstrap_js_gz_end - bootstrap_js_gz_start);
 		    httpd_resp_send(req, (const char *)bootstrap_js_gz_start, file_size);
 		}
-	else if(strstr(line, "GET /bootstrap.css")) {
+	else if(strstr(filename, "bootstrap.css")) {
 			set_content_type_from_file(req, filename);
 			httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
 		    const size_t file_size = (bootstrap_css_gz_end - bootstrap_css_gz_start);
 		    httpd_resp_send(req, (const char *)bootstrap_css_gz_start, file_size);
 		}
 	else {
-	   ESP_LOGE(TAG, "Unknown resource: %s", filepath);
+	   ESP_LOGE_LOC(TAG, "Unknown resource [%s] from path [%s] ", filename,filepath);
 	   /* Respond with 404 Not Found */
 	   httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist");
 	   return ESP_FAIL;
    }
-   ESP_LOGI(TAG, "Resource sending complete");
+   ESP_LOGI_LOC(TAG, "Resource sending complete");
    return ESP_OK;
 
 }
 esp_err_t ap_scan_handler(httpd_req_t *req){
     const char empty[] = "{}";
-	ESP_LOGI(TAG, "serving [%s]", req->uri);
-    if(!is_user_authenticated(httpd_req_t *req)){
+	ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
 	wifi_manager_scan_async();
 	esp_err_t err = set_content_type_from_req(req);
 	if(err == ESP_OK){
-		httpd_resp_send(req, (const char *)empty, strlen(empty));
+		httpd_resp_send(req, (const char *)empty, HTTPD_RESP_USE_STRLEN);
 	}
 	return err;
 }
 esp_err_t ap_get_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
-    if(!is_user_authenticated(httpd_req_t *req)){
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
     /* if we can get the mutex, write the last version of the AP list */
 	esp_err_t err = set_content_type_from_req(req);
-	if(err == ESP_OK wifi_manager_lock_json_buffer(( TickType_t ) 10)){
+	if( err == ESP_OK && wifi_manager_lock_json_buffer(( TickType_t ) 10)){
 		char *buff = wifi_manager_alloc_get_ap_list_json();
 		wifi_manager_unlock_json_buffer();
 		if(buff!=NULL){
-			httpd_resp_send(req, (const char *)buff, strlen(buff));
+			httpd_resp_send(req, (const char *)buff, HTTPD_RESP_USE_STRLEN);
 			free(buff);
 		}
 		else {
-			ESP_LOGD(TAG,  "Error retrieving ap list json string. ");
+			ESP_LOGD_LOC(TAG,  "Error retrieving ap list json string. ");
 			httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to retrieve AP list");
 		}
 	}
 	else {
 		httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "AP list unavailable");
-		ESP_LOGE(TAG,   "GET /ap.json failed to obtain mutex");
+		ESP_LOGE_LOC(TAG,   "GET /ap.json failed to obtain mutex");
 	}
 	return err;
 }
 
 esp_err_t config_get_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
-    if(!is_user_authenticated(httpd_req_t *req)){
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
@@ -337,13 +433,13 @@ esp_err_t config_get_handler(httpd_req_t *req){
 	if(err == ESP_OK){
 		char * json = config_alloc_get_json(false);
 		if(json==NULL){
-			ESP_LOGD(TAG,  "Error retrieving config json string. ");
+			ESP_LOGD_LOC(TAG,  "Error retrieving config json string. ");
 			httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Error retrieving configuration object");
 			err=ESP_FAIL;
 		}
 		else {
-			ESP_LOGD(TAG,  "config json : %s",json );
-			httpd_resp_send(req, (const char *)json, strlen(json));
+			ESP_LOGD_LOC(TAG,  "config json : %s",json );
+			httpd_resp_send(req, (const char *)json, HTTPD_RESP_USE_STRLEN);
 			free(json);
 		}
 	}
@@ -358,84 +454,122 @@ esp_err_t post_handler_buff_receive(httpd_req_t * req){
     int received = 0;
     if (total_len >= SCRATCH_BUFSIZE) {
         /* Respond with 500 Internal Server Error */
+    	ESP_LOGE_LOC(TAG,"Received content was too long. ");
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Content too long");
-        return ESP_FAIL;
+        err = ESP_FAIL;
     }
-    while (cur_len < total_len) {
+    while (err == ESP_OK && cur_len < total_len) {
         received = httpd_req_recv(req, buf + cur_len, total_len);
         if (received <= 0) {
             /* Respond with 500 Internal Server Error */
-            httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Failed to post control value");
-            return ESP_FAIL;
+        	ESP_LOGE_LOC(TAG,"Not all data was received. ");
+            httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Not all data was received");
+            err = ESP_FAIL;
+        }
+        else {
+        	cur_len += received;
         }
-        cur_len += received;
     }
 
-    buf[total_len] = '\0';
+    if(err == ESP_OK) {
+    	buf[total_len] = '\0';
+    }
+    return err;
 }
+
 esp_err_t config_post_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
 	bool bOTA=false;
 	char * otaURL=NULL;
     esp_err_t err = post_handler_buff_receive(req);
     if(err!=ESP_OK){
         return err;
     }
-    if(!is_user_authenticated(httpd_req_t *req)){
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
     char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
     cJSON *root = cJSON_Parse(buf);
-	cJSON *item=root->next;
+    if(root == NULL){
+    	ESP_LOGE_LOC(TAG, "Parsing config json failed. Received content was: %s",buf);
+    	httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json.  Unable to parse content.");
+    	return ESP_FAIL;
+    }
+
+    char * root_str = cJSON_Print(root);
+	if(root_str!=NULL){
+		ESP_LOGE(TAG, "Processing config item: \n%s", root_str);
+		free(root_str);
+	}
+
+    cJSON *item=cJSON_GetObjectItemCaseSensitive(root, "config");
+    if(!item){
+    	ESP_LOGE_LOC(TAG, "Parsing config json failed. Received content was: %s",buf);
+    	httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json.  Unable to parse content.");
+    	err = ESP_FAIL;
+    }
+    else{
+    	// navigate to the first child of the config structure
+    	if(item->child) item=item->child;
+    }
+
 	while (item && err == ESP_OK)
 	{
 		cJSON *prev_item = item;
 		item=item->next;
-		if(prev_item->name==NULL) {
-			ESP_LOGE(TAG,"Config value does not have a name");
+		char * entry_str = cJSON_Print(prev_item);
+		if(entry_str!=NULL){
+			ESP_LOGD_LOC(TAG, "Processing config item: \n%s", entry_str);
+			free(entry_str);
+		}
+
+		if(prev_item->string==NULL) {
+			ESP_LOGD_LOC(TAG,"Config value does not have a name");
 			httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json.  Value does not have a name.");
 			err = ESP_FAIL;
 		}
 		if(err == ESP_OK){
-			ESP_LOGI(TAG,"Found config value name [%s]", prev_item->name);
+			ESP_LOGI_LOC(TAG,"Found config value name [%s]", prev_item->string);
 			nvs_type_t item_type=  config_get_item_type(prev_item);
 			if(item_type!=0){
 				void * val = config_safe_alloc_get_entry_value(item_type, prev_item);
 				if(val!=NULL){
-					if(strcmp(prev_item->name, "fwurl")==0) {
+					if(strcmp(prev_item->string, "fwurl")==0) {
 						if(item_type!=NVS_TYPE_STR){
-							ESP_LOGE(TAG,"Firmware url should be type %d. Found type %d instead.",NVS_TYPE_STR,item_type );
+							ESP_LOGE_LOC(TAG,"Firmware url should be type %d. Found type %d instead.",NVS_TYPE_STR,item_type );
 							httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json.  Wrong type for firmware URL.");
 							err = ESP_FAIL;
 						}
 						else {
 							// we're getting a request to do an OTA from that URL
-							ESP_LOGW(TAG,   "Found OTA request!");
+							ESP_LOGW_LOC(TAG,   "Found OTA request!");
 							otaURL=strdup(val);
 							bOTA=true;
 						}
 					}
 					else {
-						if(config_set_value(item_type, last_parm_name , last_parm) != ESP_OK){
-							ESP_LOGE(TAG,"Unable to store value for [%s]", prev_item->name);
+						if(config_set_value(item_type, prev_item->string , val) != ESP_OK){
+							ESP_LOGE_LOC(TAG,"Unable to store value for [%s]", prev_item->string);
 							httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to store config value");
 							err = ESP_FAIL;
 						}
 						else {
-							ESP_LOGI(TAG,"Successfully set value for [%s]",prev_item->name);
+							ESP_LOGI_LOC(TAG,"Successfully set value for [%s]",prev_item->string);
 						}
 					}
 					free(val);
 				}
 				else {
-					ESP_LOGE(TAG,"Value not found for [%s]", prev_item->name);
-					httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json.  Missing value for entry.");
+					char messageBuffer[101]={};
+					ESP_LOGE_LOC(TAG,"Value not found for [%s]", prev_item->string);
+					snprintf(messageBuffer,sizeof(messageBuffer),"Malformed config json.  Missing value for entry %s.",prev_item->string);
+					httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, messageBuffer);
 					err = ESP_FAIL;
 				}
 			}
 			else {
-				ESP_LOGE(TAG,"Unable to determine the type of config value [%s]", prev_item->name);
+				ESP_LOGE_LOC(TAG,"Unable to determine the type of config value [%s]", prev_item->string);
 				httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Malformed config json.  Missing value for entry.");
 				err = ESP_FAIL;
 			}
@@ -445,15 +579,15 @@ esp_err_t config_post_handler(httpd_req_t *req){
 
 	if(err==ESP_OK){
 		set_content_type_from_req(req);
-		httpd_resp_sendstr(req, "{ok}");
+		httpd_resp_sendstr(req, "{ \"result\" : \"OK\" }");
 	}
     cJSON_Delete(root);
 	if(bOTA) {
 
 #if RECOVERY_APPLICATION
-		ESP_LOGW(TAG,   "Starting process OTA for url %s",otaURL);
+		ESP_LOGW_LOC(TAG,   "Starting process OTA for url %s",otaURL);
 #else
-		ESP_LOGW(TAG,   "Restarting system to process OTA for url %s",otaURL);
+		ESP_LOGW_LOC(TAG,   "Restarting system to process OTA for url %s",otaURL);
 #endif
 		wifi_manager_reboot_ota(otaURL);
 		free(otaURL);
@@ -462,18 +596,18 @@ esp_err_t config_post_handler(httpd_req_t *req){
 
 }
 esp_err_t connect_post_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
     char success[]="{}";
     char * ssid=NULL;
     char * password=NULL;
-    char * host_name;
+    char * host_name=NULL;
 	set_content_type_from_req(req);
 	esp_err_t err = post_handler_buff_receive(req);
 	if(err!=ESP_OK){
 		return err;
 	}
 	char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
-    if(!is_user_authenticated(httpd_req_t *req)){
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
@@ -486,32 +620,32 @@ esp_err_t connect_post_handler(httpd_req_t *req){
 
 	cJSON * ssid_object = cJSON_GetObjectItem(root, "ssid");
 	if(ssid_object !=NULL){
-		ssid = (char *)config_safe_alloc_get_entry_value(ssid_object);
+		ssid = strdup(ssid_object->valuestring);
 	}
 	cJSON * password_object = cJSON_GetObjectItem(root, "pwd");
 	if(password_object !=NULL){
-		password = (char *)config_safe_alloc_get_entry_value(password_object);
+		password = strdup(password_object->valuestring);
 	}
 	cJSON * host_name_object = cJSON_GetObjectItem(root, "host_name");
 	if(host_name_object !=NULL){
-		host_name = (char *)config_safe_alloc_get_entry_value(host_name_object);
+		host_name = strdup(host_name_object->valuestring);
 	}
 	cJSON_Delete(root);
 
 	if(host_name!=NULL){
 		if(config_set_value(NVS_TYPE_STR, "host_name", host_name) != ESP_OK){
-			ESP_LOGW(TAG,  "Unable to save host name configuration");
+			ESP_LOGW_LOC(TAG,  "Unable to save host name configuration");
 		}
 	}
 
 	if(ssid !=NULL && strlen(ssid) <= MAX_SSID_SIZE && strlen(password) <= MAX_PASSWORD_SIZE  ){
 		wifi_config_t* config = wifi_manager_get_wifi_sta_config();
 		memset(config, 0x00, sizeof(wifi_config_t));
-		strlcpy(config->sta.ssid, ssid, sizeof(config->sta.ssid)+1);
+		strlcpy((char *)config->sta.ssid, ssid, sizeof(config->sta.ssid)+1);
 		if(password){
-			strlcpy(config->sta.password, password, sizeof(config->sta.password)+1);
+			strlcpy((char *)config->sta.password, password, sizeof(config->sta.password)+1);
 		}
-		ESP_LOGD(TAG,   "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password);
+		ESP_LOGD_LOC(TAG,   "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password);
 		wifi_manager_connect_async();
 		httpd_resp_send(req, (const char *)success, strlen(success));
 	}
@@ -526,8 +660,8 @@ esp_err_t connect_post_handler(httpd_req_t *req){
 }
 esp_err_t connect_delete_handler(httpd_req_t *req){
 	char success[]="{}";
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
-    if(!is_user_authenticated(httpd_req_t *req)){
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
@@ -539,8 +673,8 @@ esp_err_t connect_delete_handler(httpd_req_t *req){
 }
 esp_err_t reboot_ota_post_handler(httpd_req_t *req){
 	char success[]="{}";
-	ESP_LOGI(TAG, "serving [%s]", req->uri);
-    if(!is_user_authenticated(httpd_req_t *req)){
+	ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
@@ -550,9 +684,9 @@ esp_err_t reboot_ota_post_handler(httpd_req_t *req){
     return ESP_OK;
 }
 esp_err_t reboot_post_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
     char success[]="{}";
-    if(!is_user_authenticated(httpd_req_t *req)){
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
@@ -562,9 +696,9 @@ esp_err_t reboot_post_handler(httpd_req_t *req){
 	return ESP_OK;
 }
 esp_err_t recovery_post_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
     char success[]="{}";
-    if(!is_user_authenticated(httpd_req_t *req)){
+    if(!is_user_authenticated(req)){
     	// todo:  redirect to login page
     	// return ESP_OK;
     }
@@ -573,107 +707,62 @@ esp_err_t recovery_post_handler(httpd_req_t *req){
 	wifi_manager_reboot(RECOVERY);
 	return ESP_OK;
 }
-esp_err_t status_post_handler(httpd_req_t *req){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
-    char success[]="{}";
-    if(!is_user_authenticated(httpd_req_t *req)){
-    	// todo:  redirect to login page
-    	// return ESP_OK;
-    }
-	set_content_type_from_req(req);
 
-	if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) {
-		char *buff = wifi_manager_alloc_get_ip_info_json();
-		wifi_manager_unlock_json_buffer();
-		if(buff) {
-			httpd_resp_send(req, (const char *)buff, strlen(buff));
-			free(buff);
-		}
-		else {
-			httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Empty status object");
-		}
+bool is_captive_portal_host_name(http_req_t *req){
+	const char * host_name=NULL;
+	const char * ap_host_name=NULL;
+
+	ESP_LOGD_LOC(TAG,  "Getting adapter host name");
+	if((err  = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
+		ESP_LOGE_LOC(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(err));
 	}
 	else {
-		httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object");
+		ESP_LOGD_LOC(TAG,  "Host name is %s",host_name);
 	}
 
-	return ESP_OK;
-}
+   ESP_LOGD_LOC(TAG,  "Getting host name from request");
+	char *req_host = alloc_get_http_header(req, "Host");
 
-esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){
-    ESP_LOGI(TAG, "serving [%s]", req->uri);
-    char success[]="";
-    if(!is_user_authenticated(httpd_req_t *req)){
-    	// todo:  redirect to login page
-    	// return ESP_OK;
-    }
-    if(error != HTTPD_404_NOT_FOUND){
-    	return httpd_resp_send_err(req, error, NULL);
-    }
 
-    char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0);
-	if(ap_ip_address==NULL){
-		ESP_LOGE(TAG,  "Unable to retrieve default AP IP Address");
-		httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Unable to retrieve default AP IP Address");
-		return ESP_FAIL;
+
+
+
+	if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){
+		ESP_LOGD_LOC(TAG,  "Soft AP is enabled. getting ip info");
+		// Access point is up and running. Get the current IP address
+		tcpip_adapter_ip_info_t ip_info;
+		esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info);
+		if(ap_ip_err != ESP_OK){
+			ESP_LOGE_LOC(TAG,  "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err));
+		}
+		else {
+			ESP_LOGD_LOC(TAG,  "getting host name for TCPIP_ADAPTER_IF_AP");
+			if((hn_err  = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) {
+				ESP_LOGE_LOC(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(hn_err));
+				err=err==ESP_OK?hn_err:err;
+			}
+			else {
+				ESP_LOGD_LOC(TAG,  "Soft AP Host name is %s",ap_host_name);
+			}
+
+			ap_ip_address =  malloc(IP4ADDR_STRLEN_MAX);
+			memset(ap_ip_address, 0x00, IP4ADDR_STRLEN_MAX);
+			if(ap_ip_address){
+				ESP_LOGD_LOC(TAG,  "Converting soft ip address to string");
+				ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX);
+				ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address);
+			}
+		}
+
 	}
 
 
-	struct httpd_req_aux *ra = req->aux;
-	//UF_HOST
 
 
-    //	ip_addr_t remote_add;
-    //	err_t err;
 
 
-    //	u16_t buflen;
-    //	u16_t port;
 
 
-    //	ESP_LOGV(TAG,  "Getting remote device IP address.");
-    //	netconn_getaddr(conn,	&remote_add,	&port,	0);
-    //	char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add)));
-    //	ESP_LOGD(TAG,  "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address);
-    //	err = netconn_recv(conn, &inbuf);
-    //	if(err == ERR_OK) {
-    //		ESP_LOGV(TAG,  "Getting data buffer.");
-    //		netbuf_data(inbuf, (void**)&buf, &buflen);
-    //		dump_net_buffer(buf, buflen);
-    //		int lenH = 0;
-    //		/* extract the first line of the request */
-    //		char *save_ptr = buf;
-    //		char *line = strtok_r(save_ptr, new_line, &save_ptr);
-    //		char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH);
-    //		char * host = malloc(lenH+1);
-    //		memset(host,0x00,lenH+1);
-    //		if(lenH>0){
-    //			strlcpy(host,temphost,lenH+1);
-    //		}
-    //		ESP_LOGD(TAG,  "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line);
-    //
-    //		if(line) {
-    //
-    //			/* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */
-    //			const char * host_name=NULL;
-    //			if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
-    //				ESP_LOGE(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(err));
-    //			}
-    //			else {
-    //				ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host);
-    //			}
-    //
-    //			/* determine if Host is from the STA IP address */
-    //			wifi_manager_lock_sta_ip_string(portMAX_DELAY);
-    //			bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false;
-    //			wifi_manager_unlock_sta_ip_string();
-    //			bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name);
-    //
-    //			if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) {
-    //				ESP_LOGI(TAG,  "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address);
-    //				netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY);
-    //				netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY);
-    //				netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY);
 
 
 
@@ -685,103 +774,231 @@ esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){
 
 
 
+    if((request_contains_hostname 		= (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){
+    	ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host);
+    }
+    else if((request_contains_hostname 		= (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){
+    	ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host);
+    }
 
+    FREE_AND_NULL(req_host);
 
 
+}
+esp_err_t redirect_200_ev_handler(httpd_req_t *req){
+	esp_err_t err=ESP_OK;
+	const char location_prefix[] = "http://";
+	char * ap_ip_address=NULL;
+	char * remote_ip=NULL;
+	const char * host_name=NULL;
+	in_port_t port=0;
+
+	ESP_LOGD_LOC(TAG,  "Getting adapter host name");
+	if((err  = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
+		ESP_LOGE_LOC(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(err));
+	}
+	else {
+		ESP_LOGD_LOC(TAG,  "Host name is %s",host_name);
+	}
 
+    ESP_LOGD_LOC(TAG,  "Getting remote socket address");
+    remote_ip = http_alloc_get_socket_address(req,0, &port);
+
+	size_t buf_size = strlen(redirect_payload1) +strlen(redirect_payload2) + strlen(redirect_payload3) +2*(strlen(location_prefix)+strlen(ap_ip_address))+1;
+	char * redirect=malloc(buf_size);
+	snprintf(redirect, buf_size,"%s%s%s%s%s%s%s",redirect_payload1, location_prefix, ap_ip_address,redirect_payload2, location_prefix, ap_ip_address,redirect_payload3);
+	ESP_LOGI_LOC(TAG,  "Redirecting host [%s] to %s",remote_ip, redirect);
+	httpd_resp_set_type(req, "text/plain");
+	httpd_resp_set_hdr(req,"Cache-Control","no-cache");
+	httpd_resp_set_status(req, "200 OK");
+	httpd_resp_send(req, redirect, HTTPD_RESP_USE_STRLEN);
+	FREE_AND_NULL(redirect);
+	FREE_AND_NULL(ap_ip_address);
+	FREE_AND_NULL(remote_ip);
+	return ESP_OK;
+}
+esp_err_t redirect_processor(httpd_req_t *req, httpd_err_code_t error){
+	esp_err_t err=ESP_OK;
+
+	const char location_prefix[] = "http://";
+	const char * host_name=NULL;
+	const char * ap_host_name=NULL;
+	char * user_agent=NULL;
+	char * remote_ip=NULL;
+	char * sta_ip_address=NULL;
+	char * ap_ip_address=NULL;
+	char * socket_local_address=NULL;
+	char * redirect  = NULL;
+	bool request_contains_hostname = false;
+	bool request_contains_ap_ip_address 	= false;
+	bool request_is_sta_ip_address 	= false;
+	bool connected_to_ap_ip_interface 	= false;
+	bool connected_to_sta_ip_interface = false;
+	bool useragentiscaptivenetwork = false;
+
+	ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(wifi_manager_lock_sta_ip_string(portMAX_DELAY)){
+		sta_ip_address = strdup(wifi_manager_get_sta_ip_string());
+		wifi_manager_unlock_sta_ip_string();
+	}
+	else {
+    	ESP_LOGE(TAG,"Unable to obtain local IP address from WiFi Manager.");
+    	httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , NULL);
+	}
 
+    in_port_t port=0;
+    ESP_LOGD_LOC(TAG,  "Getting remote socket address");
+    remote_ip = http_alloc_get_socket_address(req,0, &port);
 
+    ESP_LOGD_LOC(TAG,  "Getting host name from request");
+    char *req_host = alloc_get_http_header(req, "Host");
 
+    user_agent = alloc_get_http_header(req,"User-Agent");
+    if((useragentiscaptivenetwork = strcasestr(user_agent,"CaptiveNetworkSupport"))==true){
+    	ESP_LOGD_LOC(TAG,"Found user agent that supports captive networks! [%s]",user_agent);
+    }
 
+	esp_err_t hn_err = ESP_OK;
+	ESP_LOGD_LOC(TAG,  "Getting adapter host name");
+	if((hn_err  = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
+		ESP_LOGE_LOC(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(hn_err));
+		err=err==ESP_OK?hn_err:err;
+	}
+	else {
+		ESP_LOGD_LOC(TAG,  "Host name is %s",host_name);
+	}
 
 
+	in_port_t loc_port=0;
+	ESP_LOGD_LOC(TAG,  "Getting local socket address");
+	socket_local_address= http_alloc_get_socket_address(req,1, &loc_port);
 
+	ESP_LOGD_LOC(TAG,  "checking if soft AP is enabled");
+	if(tcpip_adapter_is_netif_up(TCPIP_ADAPTER_IF_AP)){
+		ESP_LOGD_LOC(TAG,  "Soft AP is enabled. getting ip info");
+		// Access point is up and running. Get the current IP address
+		tcpip_adapter_ip_info_t ip_info;
+		esp_err_t ap_ip_err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip_info);
+		if(ap_ip_err != ESP_OK){
+			ESP_LOGE_LOC(TAG,  "Unable to get local AP ip address. Error: %s",esp_err_to_name(ap_ip_err));
+		}
+		else {
+			ESP_LOGD_LOC(TAG,  "getting host name for TCPIP_ADAPTER_IF_AP");
+			if((hn_err  = tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &ap_host_name )) !=ESP_OK) {
+				ESP_LOGE_LOC(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(hn_err));
+				err=err==ESP_OK?hn_err:err;
+			}
+			else {
+				ESP_LOGD_LOC(TAG,  "Soft AP Host name is %s",ap_host_name);
+			}
 
+			ap_ip_address =  malloc(IP4ADDR_STRLEN_MAX);
+			memset(ap_ip_address, 0x00, IP4ADDR_STRLEN_MAX);
+			if(ap_ip_address){
+				ESP_LOGD_LOC(TAG,  "Converting soft ip address to string");
+				ip4addr_ntoa_r(&ip_info.ip, ap_ip_address, IP4ADDR_STRLEN_MAX);
+				ESP_LOGD_LOC(TAG,"TCPIP_ADAPTER_IF_AP is up and has ip address %s ", ap_ip_address);
+			}
+		}
 
+	}
 
+    ESP_LOGD_LOC(TAG,  "Peer IP: %s [port %u], System AP IP address: %s, System host: %s. Requested Host: [%s], uri [%s]",STR_OR_NA(remote_ip), port, STR_OR_NA(ap_ip_address), STR_OR_NA(host_name), STR_OR_NA(req_host), req->uri);
+    /* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */
+	/* determine if Host is from the STA IP address */
 
+    if((request_contains_hostname 		= (host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,host_name)) == true){
+    	ESP_LOGD_LOC(TAG,"http request host = system host name %s", req_host);
+    }
+    else if((request_contains_hostname 		= (ap_host_name!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_host_name)) == true){
+    	ESP_LOGD_LOC(TAG,"http request host = AP system host name %s", req_host);
+    }
+    if((request_contains_ap_ip_address 	= (ap_ip_address!=NULL) && (req_host!=NULL) && strcasestr(req_host,ap_ip_address))== true){
+    	ESP_LOGD_LOC(TAG,"http request host is access point ip address %s", req_host);
+    }
+    if((connected_to_ap_ip_interface 	= (ap_ip_address!=NULL) && (socket_local_address!=NULL) && strcasestr(socket_local_address,ap_ip_address))==true){
+    	ESP_LOGD_LOC(TAG,"http request is connected to access point interface IP %s", ap_ip_address);
+    }
+    if((request_is_sta_ip_address 	= (sta_ip_address!=NULL) && (req_host!=NULL) && strcasestr(req_host,sta_ip_address))==true){
+    	ESP_LOGD_LOC(TAG,"http request host is WiFi client ip address %s", req_host);
+    }
+    if((connected_to_sta_ip_interface = (sta_ip_address!=NULL) && (socket_local_address!=NULL) && strcasestr(sta_ip_address,socket_local_address))==true){
+    	ESP_LOGD_LOC(TAG,"http request is connected to WiFi client ip address %s", sta_ip_address);
+    }
 
+   if((error == 0) || (error == HTTPD_404_NOT_FOUND && connected_to_ap_ip_interface && !(request_contains_ap_ip_address || request_contains_hostname ))) {
 
+		// known polling url's, send redirect 302
+		size_t buf_size = strlen(location_prefix) + strlen(ap_ip_address)+1;
+		redirect = malloc(buf_size);
+		snprintf(redirect, buf_size,"%s%s",location_prefix, ap_ip_address);
+		ESP_LOGI_LOC(TAG,  "Redirecting host [%s] to %s",remote_ip, redirect);
+		httpd_resp_set_type(req, "text/plain");
+		httpd_resp_set_status(req, "302 Found");
+		httpd_resp_set_hdr(req,"Location",redirect);
+		httpd_resp_send(req, "", HTTPD_RESP_USE_STRLEN);
 
+	}
+	else {
+		ESP_LOGD_LOC(TAG,"URL not found, and not processing captive portal so throw regular 404 error");
+		httpd_resp_send_err(req, error, NULL);
+	}
 
-	set_content_type_from_req(req);
-	httpd_resp_send(req, (const char *)NULL, 0);
-	wifi_manager_reboot(RECOVERY);
+	FREE_AND_NULL(socket_local_address);
+	FREE_AND_NULL(redirect);
+	FREE_AND_NULL(req_host);
+	FREE_AND_NULL(user_agent);
+
+    FREE_AND_NULL(sta_ip_address);
 	FREE_AND_NULL(ap_ip_address);
-	return ESP_OK;
+	FREE_AND_NULL(remote_ip);
+	return err;
+
 }
+esp_err_t redirect_ev_handler(httpd_req_t *req){
+	return redirect_processor(req,0);
+}
+esp_err_t status_get_handler(httpd_req_t *req){
+    ESP_LOGD_LOC(TAG, "serving [%s]", req->uri);
+    if(!is_user_authenticated(req)){
+    	// todo:  redirect to login page
+    	// return ESP_OK;
+    }
+	set_content_type_from_req(req);
 
+	if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) {
+		char *buff = wifi_manager_alloc_get_ip_info_json();
+		wifi_manager_unlock_json_buffer();
+		if(buff) {
+			httpd_resp_send(req, (const char *)buff, strlen(buff));
+			free(buff);
+		}
+		else {
+			httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Empty status object");
+		}
+	}
+	else {
+		httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR , "Error retrieving status object");
+	}
 
+	return ESP_OK;
+}
 
 
+esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error){
+	esp_err_t err = ESP_OK;
 
+    if(error != HTTPD_404_NOT_FOUND){
+    	err = httpd_resp_send_err(req, error, NULL);
+    }
+    else {
+    	err = redirect_processor(req,error);
+    }
 
 
-//void http_server_netconn_serve(struct netconn *conn) {
-//
-//	struct netbuf *inbuf;
-//	char *buf = NULL;
-//	u16_t buflen;
-//	err_t err;
-//	ip_addr_t remote_add;
-//	u16_t port;
-//	ESP_LOGV(TAG,  "Serving page.  Getting device AP address.");
-//	const char new_line[2] = "\n";
-//	char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0);
-//	if(ap_ip_address==NULL){
-//		ESP_LOGE(TAG,  "Unable to retrieve default AP IP Address");
-//		netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
-//		netconn_close(conn);
-//		return;
-//	}
-//	ESP_LOGV(TAG,  "Getting remote device IP address.");
-//	netconn_getaddr(conn,	&remote_add,	&port,	0);
-//	char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add)));
-//	ESP_LOGD(TAG,  "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address);
-//	err = netconn_recv(conn, &inbuf);
-//	if(err == ERR_OK) {
-//		ESP_LOGV(TAG,  "Getting data buffer.");
-//		netbuf_data(inbuf, (void**)&buf, &buflen);
-//		dump_net_buffer(buf, buflen);
-//		int lenH = 0;
-//		/* extract the first line of the request */
-//		char *save_ptr = buf;
-//		char *line = strtok_r(save_ptr, new_line, &save_ptr);
-//		char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH);
-//		char * host = malloc(lenH+1);
-//		memset(host,0x00,lenH+1);
-//		if(lenH>0){
-//			strlcpy(host,temphost,lenH+1);
-//		}
-//		ESP_LOGD(TAG,  "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line);
-//
-//		if(line) {
-//
-//			/* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */
-//			const char * host_name=NULL;
-//			if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
-//				ESP_LOGE(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(err));
-//			}
-//			else {
-//				ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host);
-//			}
-//
-//			/* determine if Host is from the STA IP address */
-//			wifi_manager_lock_sta_ip_string(portMAX_DELAY);
-//			bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false;
-//			wifi_manager_unlock_sta_ip_string();
-//			bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name);
-//
-//			if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) {
-//				ESP_LOGI(TAG,  "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address);
-//				netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY);
-//				netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY);
-//				netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY);
-//			}
-//			else {
-//                //static stuff
-//
-//}
+	return err;
+}
+
 
 
 

+ 23 - 3
components/wifi-manager/http_server_handlers.h

@@ -37,6 +37,7 @@ function to process requests, decode URLs, serve files, etc. etc.
 #include <string.h>
 #include <stdlib.h>
 #include <stdbool.h>
+#include "esp_http_server.h"
 #include "wifi_manager.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
@@ -58,10 +59,21 @@ function to process requests, decode URLs, serve files, etc. etc.
 #include "lwip/priv/api_msg.h"
 #include "lwip/priv/tcp_priv.h"
 #include "lwip/priv/tcpip_priv.h"
+#include "esp_vfs.h"
+#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
+
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+
+#define ESP_LOGE_LOC(t,str, ...)  ESP_LOGE(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define ESP_LOGI_LOC(t,str, ...)  ESP_LOGI(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define ESP_LOGD_LOC(t,str, ...)  ESP_LOGD(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define ESP_LOGW_LOC(t,str, ...)  ESP_LOGW(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define ESP_LOGV_LOC(t,str, ...)  ESP_LOGV(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
+
+
 esp_err_t root_get_handler(httpd_req_t *req);
 esp_err_t resource_filehandler(httpd_req_t *req);
 esp_err_t resource_filehandler(httpd_req_t *req);
@@ -77,12 +89,20 @@ esp_err_t connect_delete_handler(httpd_req_t *req);
 esp_err_t reboot_ota_post_handler(httpd_req_t *req);
 esp_err_t reboot_post_handler(httpd_req_t *req);
 esp_err_t recovery_post_handler(httpd_req_t *req);
-esp_err_t status_post_handler(httpd_req_t *req);
+esp_err_t status_get_handler(httpd_req_t *req);
 esp_err_t ap_scan_handler(httpd_req_t *req);
-esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error);
+esp_err_t redirect_ev_handler(httpd_req_t *req);
+esp_err_t redirect_200_ev_handler(httpd_req_t *req);
 
 
+esp_err_t err_handler(httpd_req_t *req, httpd_err_code_t error);
+#define SCRATCH_BUFSIZE (10240)
+#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
 
+typedef struct rest_server_context {
+    char base_path[ESP_VFS_PATH_MAX + 1];
+    char scratch[SCRATCH_BUFSIZE];
+} rest_server_context_t;
 /**
  * @brief RTOS task for the HTTP server. Do not start manually.
  * @see void http_server_start()
@@ -93,7 +113,7 @@ void CODE_RAM_LOCATION http_server(void *pvParameters);
 void CODE_RAM_LOCATION http_server_netconn_serve(struct netconn *conn);
 
 /* @brief create the task for the http server */
-void CODE_RAM_LOCATION http_server_start();
+esp_err_t CODE_RAM_LOCATION http_server_start();
 
 /**
  * @brief gets a char* pointer to the first occurence of header_name withing the complete http request request.

+ 10 - 10
components/wifi-manager/index.html

@@ -5,19 +5,19 @@
         <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
         <meta name="apple-mobile-web-app-capable" content="yes" />
         <!-- TODO delete -->
-        <link rel="stylesheet" href="/test/bootstrap.min.css">
-        <link rel="stylesheet" href="/bootstrap.css">
-        <link rel="stylesheet" href="/style.css">
-        <script src="/jquery.js"></script>
-        <script src="/popper.js"></script>
-        <script src="/bootstrap.js"></script>
+        <link rel="stylesheet" href="/res/test/bootstrap.min.css">
+        <link rel="stylesheet" href="/res/bootstrap.css">
+        <link rel="stylesheet" href="/res/style.css">
+        <script src="/res/jquery.js"></script>
+        <script src="/res/popper.js"></script>
+        <script src="/res/bootstrap.js"></script>
 
         <!-- TODO delete -->
-        <script src="/test/jquery.min.js"></script>
-        <script src="/test/popper.min.js"></script>
-        <script src="/test/bootstrap.min.js"></script>
+        <script src="/res/test/jquery.min.js"></script>
+        <script src="/res/test/popper.min.js"></script>
+        <script src="/res/test/bootstrap.min.js"></script>
 
-        <script src="/code.js"></script>
+        <script src="/res/code.js"></script>
 
 
         <title>esp32-wifi-manager</title>

+ 3 - 2
components/wifi-manager/wifi_manager.c

@@ -63,6 +63,7 @@ Contains the freeRTOS task and all necessary support
 #include "cmd_system.h"
 #include "http_server_handlers.h"
 
+
 #ifndef RECOVERY_APPLICATION
 #define RECOVERY_APPLICATION 0
 #endif
@@ -509,7 +510,7 @@ char * get_mac_string(uint8_t mac[6]){
 
 	char * macStr=malloc(LOCAL_MAC_SIZE);
 	memset(macStr, 0x00, LOCAL_MAC_SIZE);
-	snprintf(macStr, LOCAL_MAC_SIZE-1,MACSTR, MAC2STR(mac));
+	snprintf(macStr, LOCAL_MAC_SIZE,MACSTR, MAC2STR(mac));
 	return macStr;
 
 }
@@ -1093,7 +1094,7 @@ void wifi_manager( void * pvParameters ){
 	BaseType_t xStatus;
 	EventBits_t uxBits;
 	uint8_t	retries = 0;
-	esp_err_t err=ESP_OK;
+
 	/* start http server */
 	http_server_start();
 

+ 45 - 156
components/wifi-manager/wifi_manager_http_server.c

@@ -18,7 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
-#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
+
 #include  "http_server_handlers.h"
 #include "esp_log.h"
 #include "esp_http_server.h"
@@ -32,19 +32,8 @@
 
 static const char TAG[] = "http_server";
 
-static httpd_handle_t server = NULL;
-#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
-#define SCRATCH_BUFSIZE (10240)
-
-typedef struct rest_server_context {
-    char base_path[ESP_VFS_PATH_MAX + 1];
-    char scratch[SCRATCH_BUFSIZE];
-} rest_server_context_t;
-#define ESP_LOGE_LOC(t,str, ...)  ESP_LOGE(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define ESP_LOGI_LOC(t,str, ...)  ESP_LOGI(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
-#define ESP_LOGD_LOC(t,str, ...)  ESP_LOGD(t, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__)
-
-
+static httpd_handle_t _server = NULL;
+rest_server_context_t *rest_context = NULL;
 
 void register_common_handlers(httpd_handle_t server){
 	httpd_uri_t res_get = { .uri = "/res/*", .method = HTTP_GET, .handler = resource_filehandler, .user_ctx = rest_context };
@@ -80,43 +69,71 @@ void register_regular_handlers(httpd_handle_t server){
 
 	httpd_uri_t connect_delete = { .uri = "/connect.json", .method = HTTP_DELETE, .handler = connect_delete_handler, .user_ctx = rest_context };
 	httpd_register_uri_handler(server, &connect_delete);
+
+
+	// from https://github.com/tripflex/wifi-captive-portal/blob/master/src/mgos_wifi_captive_portal.c
+	// https://unix.stackexchange.com/questions/432190/why-isnt-androids-captive-portal-detection-triggering-a-browser-window
+	 // Known HTTP GET requests to check for Captive Portal
+
+	///kindle-wifi/wifiredirect.html Kindle when requested with com.android.captiveportallogin
+	///kindle-wifi/wifistub.html Kindle before requesting with captive portal login window (maybe for detection?)
+
+
+	httpd_uri_t connect_redirect_1 = { .uri = "/mobile/status.php", .method = HTTP_GET, .handler = redirect_200_ev_handler, .user_ctx = rest_context };// Android 8.0 (Samsung s9+)
+	httpd_register_uri_handler(server, &connect_redirect_1);
+	httpd_uri_t connect_redirect_2 = { .uri = "/generate_204", .method = HTTP_GET, .handler = redirect_200_ev_handler, .user_ctx = rest_context };// Android
+	httpd_register_uri_handler(server, &connect_redirect_2);
+	httpd_uri_t connect_redirect_3 = { .uri = "/gen_204", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Android 9.0
+	httpd_register_uri_handler(server, &connect_redirect_3);
+	httpd_uri_t connect_redirect_4 = { .uri = "/ncsi.txt", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// Windows
+	httpd_register_uri_handler(server, &connect_redirect_4);
+	httpd_uri_t connect_redirect_5 = { .uri = "/hotspot-detect.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // iOS 8/9
+	httpd_register_uri_handler(server, &connect_redirect_5);
+	httpd_uri_t connect_redirect_6 = { .uri = "/library/test/success.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context };// iOS 8/9
+	httpd_register_uri_handler(server, &connect_redirect_6);
+	httpd_uri_t connect_redirect_7 = { .uri = "/hotspotdetect.html", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // iOS
+	httpd_register_uri_handler(server, &connect_redirect_7);
+	httpd_uri_t connect_redirect_8 = { .uri = "/success.txt", .method = HTTP_GET, .handler = redirect_ev_handler, .user_ctx = rest_context }; // OSX
+	httpd_register_uri_handler(server, &connect_redirect_8);
+
+
+	ESP_LOGD(TAG,"Registering default error handler for 404");
+	httpd_register_err_handler(server, HTTPD_404_NOT_FOUND,&err_handler);
+
 }
 
 esp_err_t http_server_start()
 {
-	ESP_LOGI(REST_TAG, "Initializing HTTP Server");
-    rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
+	ESP_LOGI(TAG, "Initializing HTTP Server");
+    rest_context = calloc(1, sizeof(rest_server_context_t));
     if(rest_context==NULL){
     	ESP_LOGE(TAG,"No memory for http context");
     	return ESP_FAIL;
     }
     strlcpy(rest_context->base_path, "/res/", sizeof(rest_context->base_path));
 
-    httpd_handle_t server = NULL;
     httpd_config_t config = HTTPD_DEFAULT_CONFIG();
+    config.max_uri_handlers = 20;
+    config.max_open_sockets = 8;
     config.uri_match_fn = httpd_uri_match_wildcard;
-    //todo:  use this to configure session token?
+    //todo:  use the endpoint below to configure session token?
     // config.open_fn
 
-    ESP_LOGI(REST_TAG, "Starting HTTP Server");
-    esp_err_t err= httpd_start(&server, &config);
+    ESP_LOGI(TAG, "Starting HTTP Server");
+    esp_err_t err= httpd_start(&_server, &config);
     if(err != ESP_OK){
     	ESP_LOGE_LOC(TAG,"Start server failed");
     }
     else {
 
-    	register_common_handlers(server);
-    	register_regular_handlers(server);
+    	register_common_handlers(_server);
+    	register_regular_handlers(_server);
     }
-    register_err_handler(server, HTTPD_404_NOT_FOUND,&err_handler);
-
 
     return err;
 }
 
 
-
-
 /* Function to free context */
 void adder_free_func(void *ctx)
 {
@@ -124,135 +141,6 @@ void adder_free_func(void *ctx)
     free(ctx);
 }
 
-/* This handler keeps accumulating data that is posted to it into a per
- * socket/session context. And returns the result.
- */
-esp_err_t adder_post_handler(httpd_req_t *req)
-{
-    /* Log total visitors */
-    unsigned *visitors = (unsigned *)req->user_ctx;
-    ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors));
-
-    char buf[10];
-    char outbuf[50];
-    int  ret;
-
-    /* Read data received in the request */
-    ret = httpd_req_recv(req, buf, sizeof(buf));
-    if (ret <= 0) {
-        if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
-            httpd_resp_send_408(req);
-        }
-        return ESP_FAIL;
-    }
-
-    buf[ret] = '\0';
-    int val = atoi(buf);
-    ESP_LOGI(TAG, "/adder handler read %d", val);
-
-    /* Create session's context if not already available */
-    if (! req->sess_ctx) {
-        ESP_LOGI(TAG, "/adder allocating new session");
-        req->sess_ctx = malloc(sizeof(int));
-        req->free_ctx = adder_free_func;
-        *(int *)req->sess_ctx = 0;
-    }
-
-    /* Add the received data to the context */
-    int *adder = (int *)req->sess_ctx;
-    *adder += val;
-
-    /* Respond with the accumulated value */
-    snprintf(outbuf, sizeof(outbuf),"%d", *adder);
-    httpd_resp_send(req, outbuf, strlen(outbuf));
-    return ESP_OK;
-}
-
-/* This handler gets the present value of the accumulator */
-esp_err_t adder_get_handler(httpd_req_t *req)
-{
-    /* Log total visitors */
-    unsigned *visitors = (unsigned *)req->user_ctx;
-    ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors));
-
-    char outbuf[50];
-
-    /* Create session's context if not already available */
-    if (! req->sess_ctx) {
-        ESP_LOGI(TAG, "/adder GET allocating new session");
-        req->sess_ctx = malloc(sizeof(int));
-        req->free_ctx = adder_free_func;
-        *(int *)req->sess_ctx = 0;
-    }
-    ESP_LOGI(TAG, "/adder GET handler send %d", *(int *)req->sess_ctx);
-
-    /* Respond with the accumulated value */
-    snprintf(outbuf, sizeof(outbuf),"%d", *((int *)req->sess_ctx));
-    httpd_resp_send(req, outbuf, strlen(outbuf));
-    return ESP_OK;
-}
-
-/* This handler resets the value of the accumulator */
-esp_err_t adder_put_handler(httpd_req_t *req)
-{
-    /* Log total visitors */
-    unsigned *visitors = (unsigned *)req->user_ctx;
-    ESP_LOGI(TAG, "/adder visitor count = %d", ++(*visitors));
-
-    char buf[10];
-    char outbuf[50];
-    int  ret;
-
-    /* Read data received in the request */
-    ret = httpd_req_recv(req, buf, sizeof(buf));
-    if (ret <= 0) {
-        if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
-            httpd_resp_send_408(req);
-        }
-        return ESP_FAIL;
-    }
-
-    buf[ret] = '\0';
-    int val = atoi(buf);
-    ESP_LOGI(TAG, "/adder PUT handler read %d", val);
-
-    /* Create session's context if not already available */
-    if (! req->sess_ctx) {
-        ESP_LOGI(TAG, "/adder PUT allocating new session");
-        req->sess_ctx = malloc(sizeof(int));
-        req->free_ctx = adder_free_func;
-    }
-    *(int *)req->sess_ctx = val;
-
-    /* Respond with the reset value */
-    snprintf(outbuf, sizeof(outbuf),"%d", *((int *)req->sess_ctx));
-    httpd_resp_send(req, outbuf, strlen(outbuf));
-    return ESP_OK;
-}
-
-/* Maintain a variable which stores the number of times
- * the "/adder" URI has been visited */
-static unsigned visitors = 0;
-
-
-httpd_handle_t start_webserver(void)
-{
-    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
-    // Start the httpd server
-    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
-
-    if (httpd_start(&server, &config) == ESP_OK) {
-        // Set URI handlers
-        ESP_LOGI(TAG, "Registering URI handlers");
-        httpd_register_uri_handler(server, &adder_get);
-        httpd_register_uri_handler(server, &adder_put);
-        httpd_register_uri_handler(server, &adder_post);
-        return server;
-    }
-
-    ESP_LOGI(TAG, "Error starting server!");
-    return NULL;
-}
 
 void stop_webserver(httpd_handle_t server)
 {
@@ -264,7 +152,7 @@ void stop_webserver(httpd_handle_t server)
 
 
 
-
+#if 0
 
 if(strstr(line, "GET / ")) {
 	netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY);
@@ -481,3 +369,4 @@ netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY);
 free(host);
 
 }
+#endif

+ 13 - 38
main/config.c

@@ -70,30 +70,30 @@ void config_set_entry_changed_flag(cJSON * entry, cJSON_bool flag);
 		void * pval = config_alloc_get(nt, key);\
 		if(pval!=NULL){ *value = *(t * )pval; free(pval); return ESP_OK; }\
 		return ESP_FAIL;}
-#ifdef RECOVERY_APPLICATION
+#ifndef RECOVERY_APPLICATION
 static void * malloc_fn(size_t sz){
-
 	void * ptr = heap_caps_malloc(sz, MALLOC_CAP_SPIRAM);
 	if(ptr==NULL){
 		ESP_LOGE(TAG,"malloc_fn:  unable to allocate memory!");
 	}
 	return ptr;
 }
-static void * free_fn(void * ptr){
-	if(ptr!=NULL){
-		free(ptr);
-	}
-	else {
-		ESP_LOGW(TAG,"free_fn: Cannot free null pointer!");
-	}
-	return NULL;
-}
+//static void * free_fn(void * ptr){
+//	if(ptr!=NULL){
+//		free(ptr);
+//	}
+//	else {
+//		ESP_LOGW(TAG,"free_fn: Cannot free null pointer!");
+//	}
+//	return NULL;
+//}
 #endif
 void init_cJSON(){
+
+#ifndef RECOVERY_APPLICATION
 	static cJSON_Hooks hooks;
 	// initialize cJSON hooks it uses SPIRAM memory
 	// as opposed to IRAM
-#ifndef RECOVERY_APPLICATION
 	// In squeezelite mode, allocate memory from PSRAM.  Otherwise allocate from internal RAM
 	// as recovery will lock flash access when erasing FLASH or writing to OTA partition.
 	hooks.malloc_fn=&malloc_fn;
@@ -320,7 +320,7 @@ void * config_safe_alloc_get_entry_value(nvs_type_t nvs_type, cJSON * entry){
 	}
 
 	nvs_type_t type = config_get_entry_type(entry);
-	if(nvs_type != type){
+	if (nvs_type != type){
 		// requested value type different than the stored type
 		char * entry_str = cJSON_PrintUnformatted(entry);
 		if(entry_str!=NULL){
@@ -704,31 +704,6 @@ esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){
 	return result;
 }
 
-esp_err_t config_set_value(nvs_type_t nvs_type, const char *key, void * value){
-	esp_err_t result = ESP_OK;
-	if(!config_lock(LOCK_MAX_WAIT/portTICK_PERIOD_MS)){
-			ESP_LOGE(TAG, "Unable to lock config after %d ms",LOCK_MAX_WAIT);
-			result = ESP_FAIL;
-	}
-	cJSON * entry = config_set_value_safe(nvs_type, key, value);
-	if(entry == NULL){
-		result = ESP_FAIL;
-	}
-	else{
-		char * entry_str = cJSON_PrintUnformatted(entry);
-		if(entry_str!=NULL){
-			ESP_LOGV(TAG,"config_set_value result: \n%s",entry_str);
-			free(entry_str);
-		}
-		else {
-			ESP_LOGV(TAG,"config_set_value completed");
-		}
-
-	}
-	config_unlock();
-	return result;
-}
-
 
 
 IMPLEMENT_SET_DEFAULT(uint8_t,NVS_TYPE_U8);

+ 1 - 0
main/config.h

@@ -3,6 +3,7 @@
 #include <string.h>
 #include "esp_system.h"
 #include "nvs_utilities.h"
+#include "cJSON.h"
 
 #ifdef __cplusplus
 extern "C" {