@ -18,24 +18,32 @@ Connector to let httpd use the espfs filesystem to serve the files in it.
// The static files marked with FLAG_GZIP are compressed and will be served with GZIP compression.
// The static files marked with FLAG_GZIP are compressed and will be served with GZIP compression.
// If the client does not advertise that he accepts GZIP send following warning message (telnet users for e.g.)
// If the client does not advertise that he accepts GZIP send following warning message (telnet users for e.g.)
static const char * gzipNonSupportedMessage = " HTTP/1.0 501 Not implemented \r \n Server: esp8266-httpd/ " HTTPDVER " \r \n Connection: close \r \n Content-Type: text/plain \r \n Content-Length: 52 \r \n \r \n Your browser does not accept gzip-compressed data. \r \n " ;
static const char * gzipNonSupportedMessage = " HTTP/1.0 501 Not implemented \r \n "
" Server: esp8266-httpd/ " HTTPDVER " \r \n "
" Connection: close \r \n "
" Content-Type: text/plain \r \n "
" Content-Length: 52 \r \n "
" \r \n "
" Your browser does not accept gzip-compressed data. \r \n " ;
EspFsFile * tryOpenIndex ( char * buff , const char * path ) {
EspFsFile * tryOpenIndex ( const char * path )
{
// Try appending index.tpl
// Try appending index.tpl
char fname [ 100 ] ;
size_t url_len = strlen ( path ) ;
size_t url_len = strlen ( path ) ;
strcpy ( buff , path ) ; // add current path
strcpy ( fname , path ) ; // add current path
// add slash if not already ending with slash
// add slash if not already ending with slash
if ( path [ url_len - 1 ] ! = ' / ' ) {
if ( path [ url_len - 1 ] ! = ' / ' ) {
buff [ url_len + + ] = ' / ' ;
fname [ url_len + + ] = ' / ' ;
}
}
// add index
// add index
strcpy ( buff + url_len , " index.tpl " ) ;
strcpy ( fname + url_len , " index.tpl " ) ;
return espFsOpen ( buff ) ;
return espFsOpen ( fname ) ;
}
}
@ -43,7 +51,8 @@ EspFsFile *tryOpenIndex(char *buff, const char *path) {
//This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding
//This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding
//path in the filesystem and if it exists, passes the file through. This simulates what a normal
//path in the filesystem and if it exists, passes the file through. This simulates what a normal
//webserver would do with static files.
//webserver would do with static files.
int ICACHE_FLASH_ATTR cgiEspFsHook ( HttpdConnData * connData ) {
int ICACHE_FLASH_ATTR cgiEspFsHook ( HttpdConnData * connData )
{
EspFsFile * file = connData - > cgiData ;
EspFsFile * file = connData - > cgiData ;
int len ;
int len ;
char buff [ 1024 ] ;
char buff [ 1024 ] ;
@ -62,7 +71,7 @@ int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) {
if ( file = = NULL ) {
if ( file = = NULL ) {
// file not found
// file not found
file = tryOpenIndex ( buff , connData - > url ) ;
file = tryOpenIndex ( connData - > url ) ;
if ( file = = NULL ) {
if ( file = = NULL ) {
return HTTPD_CGI_NOTFOUND ;
return HTTPD_CGI_NOTFOUND ;
@ -115,21 +124,31 @@ int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) {
//cgiEspFsTemplate can be used as a template.
//cgiEspFsTemplate can be used as a template.
# define TEMPLATE_CHUNK 1024
typedef struct {
typedef struct {
EspFsFile * file ;
EspFsFile * file ;
void * tplArg ;
void * tplArg ;
char token [ 64 ] ;
char token [ 64 ] ;
int tokenPos ;
int tokenPos ;
char buff [ TEMPLATE_CHUNK + 1 ] ;
bool chunk_resume ;
int buff_len ;
int buff_x ;
int buff_sp ;
char * buff_e ;
} TplData ;
} TplData ;
typedef void ( * TplCallback ) ( HttpdConnData * connData , char * token , void * * arg ) ;
typedef int ( * TplCallback ) ( HttpdConnData * connData , char * token , void * * arg ) ;
int ICACHE_FLASH_ATTR cgiEspFsTemplate ( HttpdConnData * connData ) {
int ICACHE_FLASH_ATTR cgiEspFsTemplate ( HttpdConnData * connData )
{
TplData * tpd = connData - > cgiData ;
TplData * tpd = connData - > cgiData ;
int len ;
int len ;
int x , sp = 0 ;
int x , sp = 0 ;
char * e = NULL ;
char * e = NULL ;
char buff [ 1025 ] ;
if ( connData - > conn = = NULL ) {
if ( connData - > conn = = NULL ) {
//Connection aborted. Clean up.
//Connection aborted. Clean up.
@ -142,11 +161,14 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) {
if ( tpd = = NULL ) {
if ( tpd = = NULL ) {
//First call to this cgi. Open the file so we can read it.
//First call to this cgi. Open the file so we can read it.
tpd = ( TplData * ) malloc ( sizeof ( TplData ) ) ;
tpd = ( TplData * ) malloc ( sizeof ( TplData ) ) ;
tpd - > chunk_resume = false ;
tpd - > file = espFsOpen ( connData - > url ) ;
tpd - > file = espFsOpen ( connData - > url ) ;
if ( tpd - > file = = NULL ) {
if ( tpd - > file = = NULL ) {
// file not found
// file not found
tpd - > file = tryOpenIndex ( buff , connData - > url ) ;
tpd - > file = tryOpenIndex ( connData - > url ) ;
if ( tpd - > file = = NULL ) {
if ( tpd - > file = = NULL ) {
espFsClose ( tpd - > file ) ;
espFsClose ( tpd - > file ) ;
@ -169,11 +191,32 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) {
return HTTPD_CGI_MORE ;
return HTTPD_CGI_MORE ;
}
}
len = espFsRead ( tpd - > file , buff , 1024 ) ;
char * buff = tpd - > buff ;
if ( len > 0 ) {
sp = 0 ;
// resume the parser state from the last token,
// if subst. func wants more data to be sent.
if ( tpd - > chunk_resume ) {
printf ( " \n Resuming chunk... \n " ) ;
len = tpd - > buff_len ;
e = tpd - > buff_e ;
sp = tpd - > buff_sp ;
x = tpd - > buff_x ;
} else {
len = espFsRead ( tpd - > file , buff , TEMPLATE_CHUNK ) ;
tpd - > buff_len = len ;
e = buff ;
e = buff ;
for ( x = 0 ; x < len ; x + + ) {
sp = 0 ;
x = 0 ;
}
if ( len > 0 ) {
printf ( " *a " ) ;
for ( ; x < len ; x + + ) {
printf ( " *b " ) ;
if ( tpd - > tokenPos = = - 1 ) {
if ( tpd - > tokenPos = = - 1 ) {
//Inside ordinary text.
//Inside ordinary text.
if ( buff [ x ] = = ' % ' ) {
if ( buff [ x ] = = ' % ' ) {
@ -186,15 +229,40 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) {
sp + + ;
sp + + ;
}
}
} else {
} else {
printf ( " *c " ) ;
if ( buff [ x ] = = ' % ' ) {
if ( buff [ x ] = = ' % ' ) {
printf ( " *d " ) ;
if ( tpd - > tokenPos = = 0 ) {
if ( tpd - > tokenPos = = 0 ) {
//This is the second % of a %% escape string.
//This is the second % of a %% escape string.
//Send a single % and resume with the normal program flow.
//Send a single % and resume with the normal program flow.
httpdSend ( connData , " % " , 1 ) ;
httpdSend ( connData , " % " , 1 ) ;
} else {
} else {
printf ( " *e " ) ;
if ( ! tpd - > chunk_resume ) {
//This is an actual token.
//This is an actual token.
tpd - > token [ tpd - > tokenPos + + ] = 0 ; //zero-terminate token
tpd - > token [ tpd - > tokenPos + + ] = 0 ; //zero-terminate token
( ( TplCallback ) ( connData - > cgiArg ) ) ( connData , tpd - > token , & tpd - > tplArg ) ;
} else {
printf ( " *f " ) ;
}
tpd - > chunk_resume = false ;
int status = ( ( TplCallback ) ( connData - > cgiArg ) ) ( connData , tpd - > token , & tpd - > tplArg ) ;
if ( status = = HTTPD_CGI_MORE ) {
printf ( " \n Saving template pos & continuing in next run.. \n " ) ;
// wants to send more in this token's place.....
tpd - > chunk_resume = true ;
tpd - > buff_len = len ;
tpd - > buff_e = e ;
tpd - > buff_sp = sp ;
tpd - > buff_x = x ;
break ;
}
}
}
//Go collect normal chars again.
//Go collect normal chars again.
e = & buff [ x + 1 ] ;
e = & buff [ x + 1 ] ;
@ -205,11 +273,20 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) {
}
}
}
}
}
}
if ( tpd - > chunk_resume ) {
return HTTPD_CGI_MORE ;
}
//Send remaining bit.
//Send remaining bit.
if ( sp ! = 0 ) httpdSend ( connData , e , sp ) ;
if ( sp ! = 0 ) httpdSend ( connData , e , sp ) ;
if ( len ! = 1024 ) {
if ( len ! = TEMPLATE_CHUNK ) {
//We're done.
//We're done.
// let the cgi func clean it's stuff
( ( TplCallback ) ( connData - > cgiArg ) ) ( connData , NULL , & tpd - > tplArg ) ;
( ( TplCallback ) ( connData - > cgiArg ) ) ( connData , NULL , & tpd - > tplArg ) ;
espFsClose ( tpd - > file ) ;
espFsClose ( tpd - > file ) ;
free ( tpd ) ;
free ( tpd ) ;
return HTTPD_CGI_DONE ;
return HTTPD_CGI_DONE ;