|
|
@ -8,14 +8,31 @@ |
|
|
|
#include "cmd.h" |
|
|
|
#include "cmd.h" |
|
|
|
#include "serbridge.h" |
|
|
|
#include "serbridge.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// the file is responsible for handling user defined web-pages
|
|
|
|
|
|
|
|
// - collects HTML files from user image, shows them on the left frame
|
|
|
|
|
|
|
|
// - handles JSON data coming from the browser
|
|
|
|
|
|
|
|
// - handles SLIP messages coming from MCU
|
|
|
|
|
|
|
|
|
|
|
|
#define WEB_CB "webCb" |
|
|
|
#define WEB_CB "webCb" |
|
|
|
|
|
|
|
#define MAX_ARGUMENT_BUFFER_SIZE 1024 |
|
|
|
|
|
|
|
|
|
|
|
#define MAX_VARS 20 |
|
|
|
struct ArgumentBuffer |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
char argBuffer[MAX_ARGUMENT_BUFFER_SIZE]; |
|
|
|
|
|
|
|
int argBufferPtr; |
|
|
|
|
|
|
|
int numberOfArgs; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static char* web_server_reasons[] = { |
|
|
|
static char* web_server_reasons[] = { |
|
|
|
"load", "refresh", "button", "submit" |
|
|
|
"load", // readable name for RequestReason::LOAD
|
|
|
|
|
|
|
|
"refresh", // readable name for RequestReason::REFRESH
|
|
|
|
|
|
|
|
"button", // readable name for RequestReason::BUTTON
|
|
|
|
|
|
|
|
"submit" // readable name for RequestReason::SUBMIT
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this variable contains the names of the user defined pages
|
|
|
|
|
|
|
|
// this information appears at the left frame below of the built in URL-s
|
|
|
|
|
|
|
|
// format: ,"UserPage1", "/UserPage1.html", "UserPage2", "/UserPage2.html",
|
|
|
|
char * webServerPages = NULL; |
|
|
|
char * webServerPages = NULL; |
|
|
|
|
|
|
|
|
|
|
|
char * ICACHE_FLASH_ATTR WEB_UserPages() |
|
|
|
char * ICACHE_FLASH_ATTR WEB_UserPages() |
|
|
@ -23,6 +40,7 @@ char * ICACHE_FLASH_ATTR WEB_UserPages() |
|
|
|
return webServerPages; |
|
|
|
return webServerPages; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// generates the content of webServerPages variable (called at booting/web page uploading)
|
|
|
|
void ICACHE_FLASH_ATTR WEB_BrowseFiles() |
|
|
|
void ICACHE_FLASH_ATTR WEB_BrowseFiles() |
|
|
|
{ |
|
|
|
{ |
|
|
|
char buffer[1024]; |
|
|
|
char buffer[1024]; |
|
|
@ -34,37 +52,35 @@ void ICACHE_FLASH_ATTR WEB_BrowseFiles() |
|
|
|
espFsIteratorInit(userPageCtx, &it); |
|
|
|
espFsIteratorInit(userPageCtx, &it); |
|
|
|
while( espFsIteratorNext(&it) ) |
|
|
|
while( espFsIteratorNext(&it) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int nlen = os_strlen(it.name); |
|
|
|
int nameLen = os_strlen(it.name); |
|
|
|
if( nlen >= 6 ) |
|
|
|
if( nameLen >= 6 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if( os_strcmp( it.name + nlen-5, ".html" ) == 0 ) |
|
|
|
// fetch HTML files
|
|
|
|
|
|
|
|
if( os_strcmp( it.name + nameLen-5, ".html" ) == 0 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char sh_name[17]; |
|
|
|
int slashPos = nameLen - 5; |
|
|
|
|
|
|
|
|
|
|
|
int spos = nlen-5; |
|
|
|
// chop path and .html from the name
|
|
|
|
|
|
|
|
while( slashPos > 0 && it.name[slashPos-1] != '/' ) |
|
|
|
while( spos > 0 ) |
|
|
|
slashPos--; |
|
|
|
{ |
|
|
|
|
|
|
|
if( it.name[spos+1] == '/' ) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
spos--; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ps = nlen-5-spos; |
|
|
|
// here we check buffer overrun
|
|
|
|
if( ps > 16 ) |
|
|
|
int maxLen = 10 + os_strlen( it.name ) + (nameLen - slashPos -5); |
|
|
|
ps = 16; |
|
|
|
if( maxLen >= sizeof(buffer) ) |
|
|
|
os_memcpy(sh_name, it.name + spos, ps); |
|
|
|
break; |
|
|
|
sh_name[ps] = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
os_strcat(buffer, ", \""); |
|
|
|
os_strcat(buffer, ", \""); |
|
|
|
os_strcat(buffer, sh_name); |
|
|
|
|
|
|
|
|
|
|
|
int writePos = os_strlen(buffer); |
|
|
|
|
|
|
|
for( int i=slashPos; i < nameLen-5; i++ ) |
|
|
|
|
|
|
|
buffer[writePos++] = it.name[i]; |
|
|
|
|
|
|
|
buffer[writePos] = 0; // terminating zero
|
|
|
|
|
|
|
|
|
|
|
|
os_strcat(buffer, "\", \"/"); |
|
|
|
os_strcat(buffer, "\", \"/"); |
|
|
|
os_strcat(buffer, it.name); |
|
|
|
os_strcat(buffer, it.name); |
|
|
|
os_strcat(buffer, "\""); |
|
|
|
os_strcat(buffer, "\""); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if( os_strlen(buffer) > 600 ) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -76,6 +92,7 @@ void ICACHE_FLASH_ATTR WEB_BrowseFiles() |
|
|
|
os_memcpy( webServerPages, buffer, len ); |
|
|
|
os_memcpy( webServerPages, buffer, len ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// initializer
|
|
|
|
void ICACHE_FLASH_ATTR WEB_Init() |
|
|
|
void ICACHE_FLASH_ATTR WEB_Init() |
|
|
|
{ |
|
|
|
{ |
|
|
|
espFsInit(userPageCtx, (void *)getUserPageSectionStart(), ESPFS_FLASH); |
|
|
|
espFsInit(userPageCtx, (void *)getUserPageSectionStart(), ESPFS_FLASH); |
|
|
@ -83,288 +100,339 @@ void ICACHE_FLASH_ATTR WEB_Init() |
|
|
|
os_printf("Valid user file system found!\n"); |
|
|
|
os_printf("Valid user file system found!\n"); |
|
|
|
else |
|
|
|
else |
|
|
|
os_printf("No user file system found!\n"); |
|
|
|
os_printf("No user file system found!\n"); |
|
|
|
WEB_BrowseFiles(); |
|
|
|
WEB_BrowseFiles(); // collect user defined HTML files
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ICACHE_FLASH_ATTR WEB_CgiJsonHook(HttpdConnData *connData) |
|
|
|
// initializes the argument buffer
|
|
|
|
|
|
|
|
static void WEB_argInit(struct ArgumentBuffer * argBuffer) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
|
|
|
argBuffer->numberOfArgs = 0; |
|
|
|
|
|
|
|
argBuffer->argBufferPtr = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void * cgiData = connData->cgiData; |
|
|
|
// adds an argument to the argument buffer (returns 0 if successful)
|
|
|
|
|
|
|
|
static int WEB_addArg(struct ArgumentBuffer * argBuffer, char * arg, int argLen ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if( argBuffer->argBufferPtr + argLen + sizeof(int) >= MAX_ARGUMENT_BUFFER_SIZE ) |
|
|
|
|
|
|
|
return -1; // buffer overflow
|
|
|
|
|
|
|
|
|
|
|
|
if( cgiData == NULL ) |
|
|
|
os_memcpy(argBuffer->argBuffer + argBuffer->argBufferPtr, &argLen, sizeof(int)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( argLen != 0 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if( !flashConfig.slip_enable ) |
|
|
|
os_memcpy( argBuffer->argBuffer + argBuffer->argBufferPtr + sizeof(int), arg, argLen ); |
|
|
|
{ |
|
|
|
argBuffer->numberOfArgs++; |
|
|
|
errorResponse(connData, 400, "Slip processing is disabled!"); |
|
|
|
} |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CmdCallback* cb = cmdGetCbByName( WEB_CB ); |
|
|
|
|
|
|
|
if( cb == NULL ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 500, "No MCU callback is registered!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if( serbridgeInProgramming() ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 500, "Slip disabled at programming mode!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char reasonBuf[16]; |
|
|
|
argBuffer->argBufferPtr += argLen + sizeof(int); |
|
|
|
int i; |
|
|
|
return 0; |
|
|
|
int len = httpdFindArg(connData->getArgs, "reason", reasonBuf, sizeof(reasonBuf)); |
|
|
|
} |
|
|
|
if( len < 0 ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 400, "No reason specified!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RequestReason reason = INVALID; |
|
|
|
// creates and sends a SLIP message from the argument buffer
|
|
|
|
for(i=0; i < sizeof(web_server_reasons)/sizeof(char *); i++) |
|
|
|
static void WEB_sendArgBuffer(struct ArgumentBuffer * argBuffer, HttpdConnData *connData, int id, RequestReason reason) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if( os_strcmp( web_server_reasons[i], reasonBuf ) == 0 ) |
|
|
|
cmdResponseStart(CMD_WEB_REQ_CB, id, 4 + argBuffer->numberOfArgs); |
|
|
|
reason = (RequestReason)i; |
|
|
|
uint16_t r = (uint16_t)reason; |
|
|
|
} |
|
|
|
cmdResponseBody(&r, sizeof(uint16_t)); // 1st argument: reason
|
|
|
|
|
|
|
|
cmdResponseBody(&connData->conn->proto.tcp->remote_ip, 4); // 2nd argument: IP
|
|
|
|
|
|
|
|
cmdResponseBody(&connData->conn->proto.tcp->remote_port, sizeof(uint16_t)); // 3rd argument: port
|
|
|
|
|
|
|
|
cmdResponseBody(connData->url, os_strlen(connData->url)); // 4th argument: URL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int p = 0; |
|
|
|
|
|
|
|
for( int j=0; j < argBuffer->numberOfArgs; j++ ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int argLen; |
|
|
|
|
|
|
|
os_memcpy( &argLen, argBuffer->argBuffer + p, sizeof(int) ); |
|
|
|
|
|
|
|
|
|
|
|
if( reason == INVALID ) |
|
|
|
char * arg = argBuffer->argBuffer + p + sizeof(int); |
|
|
|
{ |
|
|
|
cmdResponseBody(arg, argLen); |
|
|
|
errorResponse(connData, 400, "Invalid reason!"); |
|
|
|
p += argLen + sizeof(int); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cmdResponseEnd(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this method processes SLIP data from MCU and converts to JSON
|
|
|
|
|
|
|
|
// this method receives JSON from the browser, sends SLIP data to MCU
|
|
|
|
|
|
|
|
static int ICACHE_FLASH_ATTR WEB_handleJSONRequest(HttpdConnData *connData) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if( !flashConfig.slip_enable ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 400, "Slip processing is disabled!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CmdCallback* cb = cmdGetCbByName( WEB_CB ); |
|
|
|
|
|
|
|
if( cb == NULL ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 500, "No MCU callback is registered!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if( serbridgeInProgramming() ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 500, "Slip disabled at uploading program onto the MCU!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char reasonBuf[16]; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
int len = httpdFindArg(connData->getArgs, "reason", reasonBuf, sizeof(reasonBuf)); |
|
|
|
|
|
|
|
if( len < 0 ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 400, "No reason specified!"); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
char body[1024]; |
|
|
|
RequestReason reason = INVALID; |
|
|
|
int bodyPtr = 0; |
|
|
|
for(i=0; i < sizeof(web_server_reasons)/sizeof(char *); i++) |
|
|
|
int argNum = 0; |
|
|
|
{ |
|
|
|
char *argPos[MAX_VARS]; |
|
|
|
if( os_strcmp( web_server_reasons[i], reasonBuf ) == 0 ) |
|
|
|
int argLen[MAX_VARS]; |
|
|
|
reason = (RequestReason)i; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch(reason) |
|
|
|
if( reason == INVALID ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
case BUTTON: |
|
|
|
errorResponse(connData, 400, "Invalid reason!"); |
|
|
|
argLen[0] = httpdFindArg(connData->getArgs, "id", body, sizeof(body)); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
if( argLen[0] <= 0 ) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ArgumentBuffer argBuffer; |
|
|
|
|
|
|
|
WEB_argInit( &argBuffer ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch(reason) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
case BUTTON: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
char id_buf[40]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int id_len = httpdFindArg(connData->getArgs, "id", id_buf, sizeof(id_buf)); |
|
|
|
|
|
|
|
if( id_len <= 0 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
errorResponse(connData, 400, "No button ID specified!"); |
|
|
|
errorResponse(connData, 400, "No button ID specified!"); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
argPos[0] = body; |
|
|
|
if( WEB_addArg(&argBuffer, id_buf, id_len) ) |
|
|
|
argNum++; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SUBMIT: |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
if( connData->post->received < connData->post->len ) |
|
|
|
errorResponse(connData, 400, "Post too large!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SUBMIT: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if( connData->post->received < connData->post->len ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 400, "Post too large!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int bptr = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while( bptr < connData->post->len ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
char * line = connData->post->buff + bptr; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * eo = os_strchr(line, '&' ); |
|
|
|
|
|
|
|
if( eo != NULL ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
*eo = 0; |
|
|
|
|
|
|
|
bptr = eo - connData->post->buff + 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
errorResponse(connData, 400, "Post too large!"); |
|
|
|
eo = line + os_strlen( line ); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
bptr = connData->post->len; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int bptr = 0; |
|
|
|
int len = os_strlen(line); |
|
|
|
|
|
|
|
while( len >= 1 && ( line[len-1] == '\r' || line[len-1] == '\n' )) |
|
|
|
|
|
|
|
len--; |
|
|
|
|
|
|
|
line[len] = 0; |
|
|
|
|
|
|
|
|
|
|
|
while( bptr < connData->post->len ) |
|
|
|
char * val = os_strchr(line, '='); |
|
|
|
|
|
|
|
if( val != NULL ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if( argNum >= MAX_VARS ) |
|
|
|
*val = 0; |
|
|
|
|
|
|
|
char * name = line; |
|
|
|
|
|
|
|
int vblen = os_strlen(val+1) * 2; |
|
|
|
|
|
|
|
char value[vblen]; |
|
|
|
|
|
|
|
httpdUrlDecode(val+1, strlen(val+1), value, vblen); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int namLen = os_strlen(name); |
|
|
|
|
|
|
|
int valLen = os_strlen(value); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char arg[namLen + valLen + 3]; |
|
|
|
|
|
|
|
int argPtr = 0; |
|
|
|
|
|
|
|
arg[argPtr++] = (char)WEB_STRING; |
|
|
|
|
|
|
|
os_strcpy( arg + argPtr, name ); |
|
|
|
|
|
|
|
argPtr += namLen; |
|
|
|
|
|
|
|
arg[argPtr++] = 0; |
|
|
|
|
|
|
|
os_strcpy( arg + argPtr, value ); |
|
|
|
|
|
|
|
argPtr += valLen; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( WEB_addArg(&argBuffer, arg, argPtr) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
errorResponse(connData, 400, "Too many variables!"); |
|
|
|
errorResponse(connData, 400, "Post too large!"); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case LOAD: |
|
|
|
|
|
|
|
case REFRESH: |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
char * line = connData->post->buff + bptr; |
|
|
|
if( WEB_addArg(&argBuffer, NULL, 0) ) |
|
|
|
|
|
|
|
{ |
|
|
|
char * eo = os_strchr(line, '&' ); |
|
|
|
errorResponse(connData, 400, "Post too large!"); |
|
|
|
if( eo != NULL ) |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
{ |
|
|
|
} |
|
|
|
*eo = 0; |
|
|
|
|
|
|
|
bptr = eo - connData->post->buff + 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
eo = line + os_strlen( line ); |
|
|
|
|
|
|
|
bptr = connData->post->len; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int len = os_strlen(line); |
|
|
|
|
|
|
|
while( len >= 1 && ( line[len-1] == '\r' || line[len-1] == '\n' )) |
|
|
|
|
|
|
|
len--; |
|
|
|
|
|
|
|
line[len] = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char * val = os_strchr(line, '='); |
|
|
|
os_printf("Web callback to MCU: %s\n", reasonBuf); |
|
|
|
if( val != NULL ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
*val = 0; |
|
|
|
|
|
|
|
char * name = line; |
|
|
|
|
|
|
|
int vblen = os_strlen(val+1) * 2; |
|
|
|
|
|
|
|
char value[vblen]; |
|
|
|
|
|
|
|
httpdUrlDecode(val+1, strlen(val+1), value, vblen); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int namLen = os_strlen(name); |
|
|
|
WEB_sendArgBuffer(&argBuffer, connData, (uint32_t)cb->callback, reason ); |
|
|
|
int valLen = os_strlen(value); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int totallen = namLen + valLen + 2; |
|
|
|
if( reason == SUBMIT ) |
|
|
|
if( bodyPtr + totallen > sizeof(body) - 10 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
httpdStartResponse(connData, 204); |
|
|
|
errorResponse(connData, 400, "Post too large!"); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
argPos[argNum] = body + bodyPtr; |
|
|
|
return HTTPD_CGI_MORE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
body[bodyPtr++] = (char)WEB_STRING; |
|
|
|
// this method receives SLIP data from MCU sends JSON to the browser
|
|
|
|
os_strcpy( body + bodyPtr, name ); |
|
|
|
static int ICACHE_FLASH_ATTR WEB_handleMCUResponse(HttpdConnData *connData, CmdRequest * response) |
|
|
|
bodyPtr += namLen; |
|
|
|
{ |
|
|
|
body[bodyPtr++] = 0; |
|
|
|
char jsonBuf[1500]; |
|
|
|
|
|
|
|
int jsonPtr = 0; |
|
|
|
|
|
|
|
|
|
|
|
os_strcpy( body + bodyPtr, value ); |
|
|
|
|
|
|
|
bodyPtr += valLen; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
argLen[argNum++] = totallen; |
|
|
|
jsonBuf[jsonPtr++] = '{'; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case LOAD: |
|
|
|
|
|
|
|
case REFRESH: |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
os_printf("Web callback to MCU: %s\n", reasonBuf); |
|
|
|
int c = 2; |
|
|
|
|
|
|
|
while( c++ < cmdGetArgc(response) ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int len = cmdArgLen(response); |
|
|
|
|
|
|
|
char buf[len+1]; |
|
|
|
|
|
|
|
buf[len] = 0; |
|
|
|
|
|
|
|
|
|
|
|
cmdResponseStart(CMD_WEB_REQ_CB, (uint32_t)cb->callback, 4 + argNum); |
|
|
|
cmdPopArg(response, buf, len); |
|
|
|
uint16_t r = (uint16_t)reason; |
|
|
|
|
|
|
|
cmdResponseBody(&r, sizeof(uint16_t)); |
|
|
|
|
|
|
|
cmdResponseBody(&connData->conn->proto.tcp->remote_ip, 4); |
|
|
|
|
|
|
|
cmdResponseBody(&connData->conn->proto.tcp->remote_port, sizeof(uint16_t)); |
|
|
|
|
|
|
|
cmdResponseBody(connData->url, os_strlen(connData->url)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int j; |
|
|
|
if(len == 0) |
|
|
|
for( j=0; j < argNum; j++ ) |
|
|
|
break; // last argument
|
|
|
|
cmdResponseBody(argPos[j], argLen[j]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cmdResponseEnd(); |
|
|
|
if( c > 3 ) // skip the first argument
|
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = ','; |
|
|
|
|
|
|
|
|
|
|
|
if( reason == SUBMIT ) |
|
|
|
if( jsonPtr + 20 + len > sizeof(jsonBuf) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
httpdStartResponse(connData, 204); |
|
|
|
errorResponse(connData, 500, "Response too large!"); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
connData->cgiData = (void *)1; |
|
|
|
WebValueType type = (WebValueType)buf[0]; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( connData->cgiResponse != NULL ) // data from MCU
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
char jsonBuf[1500]; |
|
|
|
|
|
|
|
int jsonPtr = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int nameLen = os_strlen(buf+1); |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, buf + 1, nameLen); |
|
|
|
|
|
|
|
jsonPtr += nameLen; |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = ':'; |
|
|
|
|
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '{'; |
|
|
|
char * value = buf + 2 + nameLen; |
|
|
|
CmdRequest * req = (CmdRequest *)(connData->cgiResponse); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int c = 2; |
|
|
|
switch(type) |
|
|
|
while( c++ < cmdGetArgc(req) ) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
int len = cmdArgLen(req); |
|
|
|
case WEB_NULL: |
|
|
|
char buf[len+1]; |
|
|
|
os_memcpy(jsonBuf + jsonPtr, "null", 4); |
|
|
|
buf[len] = 0; |
|
|
|
jsonPtr += 4; |
|
|
|
|
|
|
|
break; |
|
|
|
cmdPopArg(req, buf, len); |
|
|
|
case WEB_INTEGER: |
|
|
|
|
|
|
|
{ |
|
|
|
if(len == 0) |
|
|
|
int v; |
|
|
|
break; // last argument
|
|
|
|
os_memcpy( &v, value, 4); |
|
|
|
|
|
|
|
|
|
|
|
if( c > 3 ) // skip the first argument
|
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = ','; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( jsonPtr + 20 + len > sizeof(jsonBuf) ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errorResponse(connData, 500, "Response too large!"); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WebValueType type = (WebValueType)buf[0]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int nameLen = os_strlen(buf+1); |
|
|
|
char intbuf[20]; |
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
os_sprintf(intbuf, "%d", v); |
|
|
|
os_memcpy(jsonBuf + jsonPtr, buf + 1, nameLen); |
|
|
|
os_strcpy(jsonBuf + jsonPtr, intbuf); |
|
|
|
jsonPtr += nameLen; |
|
|
|
jsonPtr += os_strlen(intbuf); |
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
} |
|
|
|
jsonBuf[jsonPtr++] = ':'; |
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_BOOLEAN: |
|
|
|
|
|
|
|
if( *value ) { |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, "true", 4); |
|
|
|
|
|
|
|
jsonPtr += 4; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, "false", 5); |
|
|
|
|
|
|
|
jsonPtr += 5; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_FLOAT: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
float f; |
|
|
|
|
|
|
|
os_memcpy( &f, value, 4); |
|
|
|
|
|
|
|
|
|
|
|
char * value = buf + 2 + nameLen; |
|
|
|
char intbuf[20]; |
|
|
|
|
|
|
|
os_sprintf(intbuf, "%f", f); |
|
|
|
|
|
|
|
os_strcpy(jsonBuf + jsonPtr, intbuf); |
|
|
|
|
|
|
|
jsonPtr += os_strlen(intbuf); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_STRING: |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
|
|
|
|
while(*value) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if( *value == '\\' || *value == '"' ) |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '\\'; |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = *(value++); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_JSON: |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, value, len - 2 - nameLen); |
|
|
|
|
|
|
|
jsonPtr += len - 2 - nameLen; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch(type) |
|
|
|
jsonBuf[jsonPtr++] = '}'; |
|
|
|
{ |
|
|
|
|
|
|
|
case WEB_NULL: |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, "null", 4); |
|
|
|
|
|
|
|
jsonPtr += 4; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_INTEGER: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int v; |
|
|
|
|
|
|
|
os_memcpy( &v, value, 4); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char intbuf[20]; |
|
|
|
noCacheHeaders(connData, 200); |
|
|
|
os_sprintf(intbuf, "%d", v); |
|
|
|
httpdHeader(connData, "Content-Type", "application/json"); |
|
|
|
os_strcpy(jsonBuf + jsonPtr, intbuf); |
|
|
|
|
|
|
|
jsonPtr += os_strlen(intbuf); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_BOOLEAN: |
|
|
|
|
|
|
|
if( *value ) { |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, "true", 4); |
|
|
|
|
|
|
|
jsonPtr += 4; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, "false", 5); |
|
|
|
|
|
|
|
jsonPtr += 5; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_FLOAT: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
float f; |
|
|
|
|
|
|
|
os_memcpy( &f, value, 4); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char intbuf[20]; |
|
|
|
char cl[16]; |
|
|
|
os_sprintf(intbuf, "%f", f); |
|
|
|
os_sprintf(cl, "%d", jsonPtr); |
|
|
|
os_strcpy(jsonBuf + jsonPtr, intbuf); |
|
|
|
httpdHeader(connData, "Content-Length", cl); |
|
|
|
jsonPtr += os_strlen(intbuf); |
|
|
|
httpdEndHeaders(connData); |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_STRING: |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
|
|
|
|
while(*value) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if( *value == '\\' || *value == '"' ) |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '\\'; |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = *(value++); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '"'; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case WEB_JSON: |
|
|
|
|
|
|
|
os_memcpy(jsonBuf + jsonPtr, value, len - 2 - nameLen); |
|
|
|
|
|
|
|
jsonPtr += len - 2 - nameLen; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
jsonBuf[jsonPtr++] = '}'; |
|
|
|
httpdSend(connData, jsonBuf, jsonPtr); |
|
|
|
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
noCacheHeaders(connData, 200); |
|
|
|
// this method is responsible for the MCU <==JSON==> Browser communication
|
|
|
|
httpdHeader(connData, "Content-Type", "application/json"); |
|
|
|
int ICACHE_FLASH_ATTR WEB_CgiJsonHook(HttpdConnData *connData) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
|
|
|
|
|
|
|
|
|
|
|
char cl[16]; |
|
|
|
void * cgiData = connData->cgiData; |
|
|
|
os_sprintf(cl, "%d", jsonPtr); |
|
|
|
|
|
|
|
httpdHeader(connData, "Content-Length", cl); |
|
|
|
|
|
|
|
httpdEndHeaders(connData); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
httpdSend(connData, jsonBuf, jsonPtr); |
|
|
|
if( cgiData == NULL ) |
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
{ |
|
|
|
|
|
|
|
connData->cgiData = (void *)1; // indicate, that request was processed
|
|
|
|
|
|
|
|
return WEB_handleJSONRequest(connData); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( connData->cgiResponse != NULL ) // data from MCU
|
|
|
|
|
|
|
|
return WEB_handleMCUResponse(connData, (CmdRequest *)(connData->cgiResponse)); |
|
|
|
|
|
|
|
|
|
|
|
return HTTPD_CGI_MORE; |
|
|
|
return HTTPD_CGI_MORE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this method is called when MCU transmits WEB_DATA command
|
|
|
|
void ICACHE_FLASH_ATTR WEB_Data(CmdPacket *cmd) |
|
|
|
void ICACHE_FLASH_ATTR WEB_Data(CmdPacket *cmd) |
|
|
|
{ |
|
|
|
{ |
|
|
|
CmdRequest req; |
|
|
|
CmdRequest req; |
|
|
@ -373,14 +441,14 @@ void ICACHE_FLASH_ATTR WEB_Data(CmdPacket *cmd) |
|
|
|
if (cmdGetArgc(&req) < 2) return; |
|
|
|
if (cmdGetArgc(&req) < 2) return; |
|
|
|
|
|
|
|
|
|
|
|
uint8_t ip[4]; |
|
|
|
uint8_t ip[4]; |
|
|
|
cmdPopArg(&req, ip, 4); |
|
|
|
cmdPopArg(&req, ip, 4); // pop the IP address
|
|
|
|
|
|
|
|
|
|
|
|
uint16_t port; |
|
|
|
uint16_t port; |
|
|
|
cmdPopArg(&req, &port, 2); |
|
|
|
cmdPopArg(&req, &port, 2); // pop the HTTP port
|
|
|
|
|
|
|
|
|
|
|
|
HttpdConnData * conn = httpdLookUpConn(ip, port); |
|
|
|
HttpdConnData * conn = httpdLookUpConn(ip, port); // look up connection based on IP/port
|
|
|
|
if( conn != NULL && conn->cgi == WEB_CgiJsonHook ) // make sure that the right CGI handler will be called
|
|
|
|
if( conn != NULL && conn->cgi == WEB_CgiJsonHook ) // make sure that the right CGI handler is configured
|
|
|
|
httpdSetCGIResponse( conn, &req ); |
|
|
|
httpdSetCGIResponse( conn, &req ); |
|
|
|
else |
|
|
|
else |
|
|
|
os_printf("WEB response ignored as no valid http connection found for the request!\n"); |
|
|
|
os_printf("WEB_DATA ignored as no valid HTTP connection found!\n"); |
|
|
|
} |
|
|
|
} |
|
|
|