//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 //webserver would do with static files. int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { EspFsFile *file=connData->cgiData; int len; char buff[1024]; if (connData->conn==NULL) { //Connection aborted. Clean up. espFsClose(file); return HTTPD_CGI_DONE; } if (file==NULL) { //First call to this cgi. Open the file so we can read it. file=espFsOpen(connData->url); if (file==NULL) { return HTTPD_CGI_NOTFOUND; } connData->cgiData=file; httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); httpdEndHeaders(connData); return HTTPD_CGI_MORE; } len=espFsRead(file, buff, 1024); if (len>0) espconn_sent(connData->conn, (uint8 *)buff, len); if (len!=1024) { //We're done. espFsClose(file); return HTTPD_CGI_DONE; } else { //Ok, till next time. return HTTPD_CGI_MORE; } }
void doWork(void *ignore) { char buff[5*1024]; ESP_LOGD(tag, "Flash address is 0x%x", (int)flashAddress); if (espFsInit(flashAddress, 64*1024) != ESPFS_INIT_RESULT_OK) { ESP_LOGD(tag, "Failed to initialize espfs"); return; } EspFsFile *fh = espFsOpen("files/test3.txt");; if (fh != NULL) { int sizeRead = 0; sizeRead = espFsRead(fh, buff, sizeof(buff)); ESP_LOGD(tag, "Result: %.*s", sizeRead, buff); size_t fileSize; char *data; sizeRead = espFsAccess(fh, (void **)&data, &fileSize); ESP_LOGD(tag, "Result from access: %.*s", fileSize, data); espFsClose(fh); vTaskDelete(NULL); } }
/* * Load a file using the ESPFS file system. The file to be loaded is specified * by the "path" parameter. If the file can be loaded, then the full data * of the file is returned and the "fileSize" size pointer is updated. * If the file can't be loaded, NULL is returned. * * If data is returned, it does NOT need to be cleaned up because the nature of * the ESPFS file system is that the data is found in flash and addressable. As * such there is no RAM cost for getting the data of such a file. * * Prior to calling this function, the espFsInit() function should have been * previously called to initialize the ESPFS environment. */ char *esp32_loadFileESPFS(char *path, size_t *fileSize) { EspFsFile *fh = espFsOpen((char *)path); if (fh == NULL) { *fileSize = 0; LOGD("ESPFS: Failed to open file %s", path); return NULL; } char *data; espFsAccess(fh, (void **)&data, fileSize); espFsClose(fh); // Note ... because data is mapped in memory from flash ... it will be good // past the file close. LOGD("esp32_loadFileESPFS: Read file %s for size %d", path, *fileSize); return data; } // esp32_loadFileESPFS
//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 //webserver would do with static files. int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { EspFsFile *file=connData->cgiData; int len; char buff[1024]; #ifdef GZIP_COMPRESSION const char *gzipSendResult = NULL; #endif if (connData->conn==NULL) { //Connection aborted. Clean up. espFsClose(file); return HTTPD_CGI_DONE; } if (file==NULL) { //First call to this cgi. Open the file so we can read it. file=espFsOpen(connData->url); if (file==NULL) { return HTTPD_CGI_NOTFOUND; } connData->cgiData=file; httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); #ifdef GZIP_COMPRESSION gzipSendResult = sendGZIPEncodingIfNeeded(connData); if (gzipSendResult != NULL) { httpdEndHeaders(connData); httpdSend(connData, gzipSendResult, os_strlen(gzipSendResult)); return HTTPD_CGI_DONE; } #endif httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); httpdEndHeaders(connData); return HTTPD_CGI_MORE; } len=espFsRead(file, buff, 1024); if (len>0) espconn_sent(connData->conn, (uint8 *)buff, len); if (len!=1024) { //We're done. espFsClose(file); return HTTPD_CGI_DONE; } else { //Ok, till next time. return HTTPD_CGI_MORE; } }
int main(int argc, char **argv) { int f, out; int len; char buff[128]; EspFsFile *ef; off_t size; if (argc!=3) { printf("Usage: %s espfs-image file\nExpands file from the espfs-image archive.\n", argv[0]); exit(0); } f=open(argv[1], O_RDONLY); if (f<=0) { perror(argv[1]); exit(1); } size=lseek(f, 0, SEEK_END); espFsData=mmap(NULL, size, PROT_READ, MAP_SHARED, f, 0); if (espFsData==MAP_FAILED) { perror("mmap"); exit(1); } ef=espFsOpen(argv[2]); if (ef==NULL) { printf("Couldn't find %s in image.\n", argv[2]); exit(1); } out=open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0644); if (out<=0) { perror(argv[2]); exit(1); } while ((len=espFsRead(ef, buff, 128))!=0) { write(out, buff, len); } espFsClose(ef); //munmap, close, ... I can't be bothered. }
//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 //webserver would do with static files. int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { EspFsFile *file=connData->cgiData; int len; char buff[1024]; char acceptEncodingBuffer[64]; int isGzip; if (connData->conn==NULL) { //Connection aborted. Clean up. espFsClose(file); return HTTPD_CGI_DONE; } if (file==NULL) { //First call to this cgi. Open the file so we can read it. file=espFsOpen(connData->url); if (file==NULL) { return HTTPD_CGI_NOTFOUND; } // The gzip checking code is intentionally without #ifdefs because checking // for FLAG_GZIP (which indicates gzip compressed file) is very easy, doesn't // mean additional overhead and is actually safer to be on at all times. // If there are no gzipped files in the image, the code bellow will not cause any harm. // Check if requested file was GZIP compressed isGzip = espFsFlags(file) & FLAG_GZIP; if (isGzip) { // Check the browser's "Accept-Encoding" header. If the client does not // advertise that he accepts GZIP send a warning message (telnet users for e.g.) httpdGetHeader(connData, "Accept-Encoding", acceptEncodingBuffer, 64); if (os_strstr(acceptEncodingBuffer, "gzip") == NULL) { //No Accept-Encoding: gzip header present httpdSend(connData, gzipNonSupportedMessage, -1); espFsClose(file); return HTTPD_CGI_DONE; } } connData->cgiData=file; httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); if (isGzip) { httpdHeader(connData, "Content-Encoding", "gzip"); } httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); httpdEndHeaders(connData); return HTTPD_CGI_MORE; } len=espFsRead(file, buff, 1024); if (len>0) espconn_sent(connData->conn, (uint8 *)buff, len); if (len!=1024) { //We're done. espFsClose(file); return HTTPD_CGI_DONE; } else { //Ok, till next time. return HTTPD_CGI_MORE; } }
int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) { TplData *tpd=connData->cgiData; int len; int x, sp=0; char *e=NULL; char buff[1025]; if (connData->conn==NULL) { //Connection aborted. Clean up. ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); espFsClose(tpd->file); os_free(tpd); return HTTPD_CGI_DONE; } if (tpd==NULL) { //First call to this cgi. Open the file so we can read it. tpd=(TplData *)os_malloc(sizeof(TplData)); tpd->file=espFsOpen(connData->url); tpd->tplArg=NULL; tpd->tokenPos=-1; if (tpd->file==NULL) { espFsClose(tpd->file); os_free(tpd); return HTTPD_CGI_NOTFOUND; } if (espFsFlags(tpd->file) & FLAG_GZIP) { debug("cgiEspFsTemplate: Trying to use gzip-compressed file %s as template!\n", connData->url); espFsClose(tpd->file); os_free(tpd); return HTTPD_CGI_NOTFOUND; } connData->cgiData=tpd; httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); httpdEndHeaders(connData); return HTTPD_CGI_MORE; } len=espFsRead(tpd->file, buff, 1024); if (len>0) { sp=0; e=buff; for (x=0; x<len; x++) { if (tpd->tokenPos==-1) { //Inside ordinary text. if (buff[x]=='%') { //Send raw data up to now if (sp!=0) httpdSend(connData, e, sp); sp=0; //Go collect token chars. tpd->tokenPos=0; } else { sp++; } } else { if (buff[x]=='%') { if (tpd->tokenPos==0) { //This is the second % of a %% escape string. //Send a single % and resume with the normal program flow. httpdSend(connData, "%", 1); } else { //This is an actual token. tpd->token[tpd->tokenPos++]=0; //zero-terminate token ((TplCallback)(connData->cgiArg))(connData, tpd->token, &tpd->tplArg); } //Go collect normal chars again. e=&buff[x+1]; tpd->tokenPos=-1; } else { if (tpd->tokenPos<(sizeof(tpd->token)-1)) tpd->token[tpd->tokenPos++]=buff[x]; } } } } //Send remaining bit. if (sp!=0) httpdSend(connData, e, sp); if (len!=1024) { //We're done. ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); espFsClose(tpd->file); os_free(tpd); return HTTPD_CGI_DONE; } else { //Ok, till next time. return HTTPD_CGI_MORE; } }
int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) { TplData *tpd=connData->cgiData; int len; int x, sp=0; char *e=NULL; char buff[1025]; if (connData->conn==NULL) { //Connection aborted. Clean up. ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); espFsClose(tpd->file); os_free(tpd); return HTTPD_CGI_DONE; } if (tpd==NULL) { //First call to this cgi. Open the file so we can read it. tpd=(TplData *)os_malloc(sizeof(TplData)); tpd->file=espFsOpen(connData->url); tpd->tplArg=NULL; tpd->tokenPos=-1; if (tpd->file==NULL) { return HTTPD_CGI_NOTFOUND; } connData->cgiData=tpd; httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); httpdEndHeaders(connData); return HTTPD_CGI_MORE; } len=espFsRead(tpd->file, buff, 1024); if (len>0) { sp=0; e=buff; for (x=0; x<len; x++) { if (tpd->tokenPos==-1) { //Inside ordinary text. if (buff[x]=='%') { //Send raw data up to now if (sp!=0) espconn_sent(connData->conn, (uint8 *)e, sp); sp=0; //Go collect token chars. tpd->tokenPos=0; } else { sp++; } } else { if (buff[x]=='%') { tpd->token[tpd->tokenPos++]=0; //zero-terminate token ((TplCallback)(connData->cgiArg))(connData, tpd->token, &tpd->tplArg); //Go collect normal chars again. e=&buff[x+1]; tpd->tokenPos=-1; } else { if (tpd->tokenPos<(sizeof(tpd->token)-1)) tpd->token[tpd->tokenPos++]=buff[x]; } } } } //Send remaining bit. if (sp!=0) espconn_sent(connData->conn, (uint8 *)e, sp); if (len!=1024) { //We're done. ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); espFsClose(tpd->file); return HTTPD_CGI_DONE; } else { //Ok, till next time. return HTTPD_CGI_MORE; } }
//cgiEspFsHtml is a simple HTML file that gets prefixed by head.tpl int ICACHE_FLASH_ATTR cgiEspFsHtml(HttpdConnData *connData) { EspFsFile *file = connData->cgiData; char buff[2048]; if (connData->conn==NULL) { // Connection aborted. Clean up. if (file != NULL) espFsClose(file); return HTTPD_CGI_DONE; } // The first time around we send the head template in one go and we open the file if (file == NULL) { int status = 200; // open file, return error on failure file = espFsOpen("/head.tpl"); if (file == NULL) { os_strcpy(buff, "Header file 'head.tpl' not found\n"); os_printf(buff); status = 500; goto error; } // read file and return it int len = espFsRead(file, buff, sizeof(buff)); espFsClose(file); if (len == sizeof(buff)) { os_sprintf(buff, "Header file 'head.tpl' too large (%d>%d)!\n", len, sizeof(buff)); os_printf(buff); status = 500; goto error; } // before returning, open the real file for next time around file = espFsOpen(connData->url); if (file == NULL) { os_strcpy(buff, connData->url); os_strcat(buff, " not found\n"); os_printf(buff); status = 404; goto error; } connData->cgiData = file; httpdStartResponse(connData, status); httpdHeader(connData, "Content-Type", "text/html; charset=UTF-8"); httpdEndHeaders(connData); httpdSend(connData, buff, len); printGlobalJSON(connData); return HTTPD_CGI_MORE; error: // error response httpdStartResponse(connData, status); httpdHeader(connData, "Content-Type", "text/html; charset=UTF-8"); httpdEndHeaders(connData); httpdSend(connData, buff, -1); return HTTPD_CGI_DONE; } // The second time around send actual file int len = espFsRead(file, buff, sizeof(buff)); httpdSend(connData, buff, len); if (len == sizeof(buff)) { return HTTPD_CGI_MORE; } else { connData->cgiData = NULL; espFsClose(file); return HTTPD_CGI_DONE; } }