diff --git a/html/index.tpl b/html/index.tpl index 80e05d1..0fbef91 100644 --- a/html/index.tpl +++ b/html/index.tpl @@ -15,6 +15,7 @@ been loaded %counter% times. can upgrade the firmware of this module.
  • You can download the raw contents of the SPI flash rom
  • Esphttpd now also supports websockets.
  • +
  • Test esphttpd using the built-in test suite
  • And because I can, here's a link to my website

    diff --git a/html/test/index.html b/html/test/index.html new file mode 100644 index 0000000..01f4121 --- /dev/null +++ b/html/test/index.html @@ -0,0 +1,9 @@ +Webserver test + + + + +
    +
    Initializing test...
    +
    + \ No newline at end of file diff --git a/html/test/test.cgi b/html/test/test.cgi new file mode 100644 index 0000000..ed00813 Binary files /dev/null and b/html/test/test.cgi differ diff --git a/html/test/test.js b/html/test/test.js new file mode 100644 index 0000000..03c0cd4 --- /dev/null +++ b/html/test/test.js @@ -0,0 +1,205 @@ + +/* +Code to test the webserver. This depends on: +- The cat images being available, for concurrent espfs testing +- the test.cgi script available, for generic data mangling tests + + +This test does a max of 4 requests in parallel. The nonos SDK supports a max of +5 connections; the default libesphttpd setting is 4 sockets at a time. Unfortunately, +the nonos sdk just closes all sockets opened after the available sockets are opened, +instead of queueing them until a socket frees up. +*/ + + +function log(line) { + $("#log").insertAdjacentHTML('beforeend', line+'
    '); +} + + +//Load an image multiple times in parallel +function testParLdImg(url, ct, doneFn) { + var im=[]; + var state={"loaded":0, "count":ct, "doneFn": doneFn, "error":false}; + for (var x=0; xthis.ts+2000) { + log("..."+Math.floor(e.loaded*100/this.len).toString()+"%"); + this.ts=Date.now(); + } + }.bind(state); + } + xhr.send(); +} + + +function testUploadCgi(len, doneFn) { + var xhr=j(); + var state={"len":len, "doneFn":doneFn, "ts": Date.now()}; + var data=""; + for (var x=0; x=200 && xhr.status<300) { + var ulen=parseInt(xhr.responseText); + if (ulen==this.len) { + log("Uploaded "+this.len+" bytes successfully."); + this.doneFn(true); + } else { + log("Webserver received "+ulen+" bytes successfully, but sent "+this.len+"!"); + this.doneFn(false); + } + } else if (xhr.readyState==4) { + log("Failed! Error "+xhr.status); + this.doneFn(false); + } + }.bind(state); + //If the webbrowser enables it, show progress. + if (typeof xhr.upload.onprogress != 'undefined') { + xhr.upload.onprogress=function(e) { + if (Date.now()>this.ts+2000) { + log("..."+Math.floor(e.loaded*100/e.total).toString()+"%"); + this.ts=Date.now(); + } + }.bind(state); + } + //Upload the file + xhr.send(data); +} + +function hammerNext(state, xhr) { + if (state.done==state.count) { + state.doneFn(!state.error); + } + if (state.started==state.count) return; + xhr.open("GET", "test.cgi?len="+state.len+"&nocache="+Math.floor(Math.random()*100000).toString()); + xhr.onreadystatechange=function(xhr) { + if (xhr.readyState==4 && xhr.status>=200 && xhr.status<300) { + if (xhr.response.length==this.len) { + state.done++; + hammerNext(this, xhr); + } else { + log("Downloaded "+xhr.response.length+" bytes successfully, but needed "+this.len+"!"); + state.done++; + hammerNext(this, xhr); + } + } else if (xhr.readyState==4) { + log("Failed! Error "+xhr.status); + state.done++; + hammerNext(this, xhr); + } + }.bind(state, xhr); + //If the webbrowser enables it, show progress. + if (typeof xhr.onprogress != 'undefined') { + xhr.onprogress=function(e) { + if (Date.now()>this.ts+2000) { + log("..."+state.done+"/"+state.count); + this.ts=Date.now(); + } + }.bind(state); + } + state.started++; + xhr.send(); +} + +function testHammer(count, par, len, doneFn) { + var state={"count":count, "started":0, "done":0, "par":par, "len":len, "doneFn":doneFn, "ts": Date.now(), "error":false}; + var xhr=[]; + for (var i=0; iSuccess!"); + successCnt++; + } else { + log("Test failed!"); + } + } + tstState++; + if (tstState==1) { + log("Testing parallel load of espfs files..."); + testParLdImg("../cats/kitten-loves-toy.jpg", 3, nextTest); + } else if (tstState==2) { + log("Testing GET request of 32K..."); + testDownloadCgi(32*1024, nextTest); + } else if (tstState==3) { + log("Testing GET request of 128K..."); + testDownloadCgi(128*1024, nextTest); + } else if (tstState==4) { + log("Testing GET request of 512K..."); + testDownloadCgi(512*1024, nextTest); + } else if (tstState==5) { + log("Testing POST request of 512 bytes..."); + testUploadCgi(512, nextTest); + } else if (tstState==6) { + log("Testing POST request of 16K bytes..."); + testUploadCgi(16*1024, nextTest); + } else if (tstState==7) { + log("Testing POST request of 512K bytes..."); + testUploadCgi(512*1024, nextTest); + } else if (tstState==8) { + log("Hammering webserver with 500 requests of size 512..."); + testHammer(500, 3, 512, nextTest); + } else if (tstState==9) { + log("Hammering webserver with 500 requests of size 2048..."); + testHammer(500, 3, 2048, nextTest); + } else { + log("Tests done! "+successCnt+" out of "+(tstState-1)+" tests were successful."); + } +} + + + +window.onload=function(e) { + log("Starting tests."); + nextTest(false); +} + + + diff --git a/libesphttpd b/libesphttpd index cdc6316..b1808d2 160000 --- a/libesphttpd +++ b/libesphttpd @@ -1 +1 @@ -Subproject commit cdc6316b126ea92723743da37945fb92cfa7c924 +Subproject commit b1808d27b08bb8915fcfd6d21784fa6069a56c37 diff --git a/user/cgi-test.c b/user/cgi-test.c new file mode 100644 index 0000000..a7e3ef5 --- /dev/null +++ b/user/cgi-test.c @@ -0,0 +1,86 @@ +/* +Cgi routines as used by the tests in the html/test subdirectory. +*/ + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * Jeroen Domburg wrote this file. As long as you retain + * this notice you can do whatever you want with this stuff. If we meet some day, + * and you think this stuff is worth it, you can buy me a beer in return. + * ---------------------------------------------------------------------------- + */ + + +#include +#include "cgi-test.h" + + +typedef struct { + int len; + int sendPos; +} TestbedState; + + +int ICACHE_FLASH_ATTR cgiTestbed(HttpdConnData *connData) { + char buff[1024]; + int first=0; + int l, x; + TestbedState *state=(TestbedState*)connData->cgiData; + + if (connData->conn==NULL) { + //Connection aborted. Clean up. + if (state) free(state); + return HTTPD_CGI_DONE; + } + + if (state==NULL) { + //First call + state=malloc(sizeof(TestbedState)); + memset(state, 0, sizeof(state)); + connData->cgiData=state; + first=1; + } + + if (connData->requestType==HTTPD_METHOD_GET) { + if (first) { + httpdStartResponse(connData, 200); + httpdHeader(connData, "content-type", "application/data"); + httpdEndHeaders(connData); + l=httpdFindArg(connData->getArgs, "len", buff, sizeof(buff)); + state->len=1024; + if (l!=-1) state->len=atoi(buff); + state->sendPos=0; + return HTTPD_CGI_MORE; + } else { + l=sizeof(buff); + if (l>(state->len-state->sendPos)) l=(state->len-state->sendPos); + //Fill with semi-random data + for (x=0; xsendPos>>10))&0x1F)+'0'; + httpdSend(connData, buff, l); + state->sendPos+=l; + printf("Test: Uploaded %d/%d bytes\n", state->sendPos, state->len); + if (state->len<=state->sendPos) { + if (state) free(state); + return HTTPD_CGI_DONE; + } else { + return HTTPD_CGI_MORE; + } + } + } + if (connData->requestType==HTTPD_METHOD_POST) { + if (connData->post->len!=connData->post->received) { + //Still receiving data. Ignore this. + printf("Test: got %d/%d bytes\n", connData->post->received, connData->post->len); + return HTTPD_CGI_MORE; + } else { + httpdStartResponse(connData, 200); + httpdHeader(connData, "content-type", "text/plain"); + httpdEndHeaders(connData); + l=sprintf(buff, "%d", connData->post->received); + httpdSend(connData, buff, l); + return HTTPD_CGI_DONE; + } + } + return HTTPD_CGI_DONE; +} diff --git a/user/cgi-test.h b/user/cgi-test.h new file mode 100644 index 0000000..ba78edc --- /dev/null +++ b/user/cgi-test.h @@ -0,0 +1,8 @@ +#ifndef CGI_TEST_H +#define CGI_TEST_H + +#include "httpd.h" + +int cgiTestbed(HttpdConnData *connData); + +#endif \ No newline at end of file diff --git a/user/user_main.c b/user/user_main.c index c61235b..e22a345 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -26,6 +26,7 @@ some pictures of cats. #include "captdns.h" #include "webpages-espfs.h" #include "cgiwebsocket.h" +#include "cgi-test.h" //The example can print out the heap use every 3 seconds. You can use this to catch memory leaks. //#define SHOW_HEAP_USE @@ -147,6 +148,10 @@ HttpdBuiltInUrl builtInUrls[]={ {"/websocket/ws.cgi", cgiWebsocket, myWebsocketConnect}, {"/websocket/echo.cgi", cgiWebsocket, myEchoWebsocketConnect}, + {"/test", cgiRedirect, "/test/index.html"}, + {"/test/", cgiRedirect, "/test/index.html"}, + {"/test/test.cgi", cgiTestbed, NULL}, + {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem {NULL, NULL, NULL} };