Refactor to make all requests able to handle streaming as it makes the code much simpler

v0.9.0
Ben Pirt 10 years ago
parent 92bb77784a
commit 4ee2d75977
  1. 12
      user/cgi.c
  2. 4
      user/cgi.h
  3. 5
      user/cgiwifi.c
  4. 2
      user/cgiwifi.h
  5. 78
      user/httpd.c
  6. 12
      user/httpd.h
  7. 30
      user/user_main.c

@ -50,9 +50,9 @@ int ICACHE_FLASH_ATTR cgiLed(HttpdConnData *connData) {
//Template code for the led page. //Template code for the led page.
void ICACHE_FLASH_ATTR tplLed(HttpdConnData *connData, char *token, void **arg) { int ICACHE_FLASH_ATTR tplLed(HttpdConnData *connData, char *token, void **arg) {
char buff[128]; char buff[128];
if (token==NULL) return; if (token==NULL) return HTTPD_CGI_DONE;
os_strcpy(buff, "Unknown"); os_strcpy(buff, "Unknown");
if (os_strcmp(token, "ledstate")==0) { if (os_strcmp(token, "ledstate")==0) {
@ -63,20 +63,22 @@ void ICACHE_FLASH_ATTR tplLed(HttpdConnData *connData, char *token, void **arg)
} }
} }
httpdSend(connData, buff, -1); httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
} }
static long hitCounter=0; static long hitCounter=0;
//Template code for the counter on the index page. //Template code for the counter on the index page.
void ICACHE_FLASH_ATTR tplCounter(HttpdConnData *connData, char *token, void **arg) { int ICACHE_FLASH_ATTR tplCounter(HttpdConnData *connData, char *token, void **arg) {
char buff[128]; char buff[128];
if (token==NULL) return; if (token==NULL) return HTTPD_CGI_DONE;
if (os_strcmp(token, "counter")==0) { if (os_strcmp(token, "counter")==0) {
hitCounter++; hitCounter++;
os_sprintf(buff, "%ld", hitCounter); os_sprintf(buff, "%ld", hitCounter);
} }
httpdSend(connData, buff, -1); httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
} }
@ -232,7 +234,7 @@ int ICACHE_FLASH_ATTR updateWeb(HttpdConnData *connData) {
if (connData->cgiPrivData!=NULL) os_free(connData->cgiPrivData); if (connData->cgiPrivData!=NULL) os_free(connData->cgiPrivData);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
}else{ }else{
return HTTPD_CGI_NOTDONE; return HTTPD_CGI_MORE;
} }
} }
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;

@ -4,9 +4,9 @@
#include "httpd.h" #include "httpd.h"
int cgiLed(HttpdConnData *connData); int cgiLed(HttpdConnData *connData);
void tplLed(HttpdConnData *connData, char *token, void **arg); int tplLed(HttpdConnData *connData, char *token, void **arg);
int cgiReadFlash(HttpdConnData *connData); int cgiReadFlash(HttpdConnData *connData);
void tplCounter(HttpdConnData *connData, char *token, void **arg); int tplCounter(HttpdConnData *connData, char *token, void **arg);
int updateWeb(HttpdConnData *connData); int updateWeb(HttpdConnData *connData);
#endif #endif

@ -231,11 +231,11 @@ int ICACHE_FLASH_ATTR cgiWifiSetMode(HttpdConnData *connData) {
} }
//Template code for the WLAN page. //Template code for the WLAN page.
void ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) { int ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) {
char buff[1024]; char buff[1024];
int x; int x;
static struct station_config stconf; static struct station_config stconf;
if (token==NULL) return; if (token==NULL) return HTTPD_CGI_DONE;
wifi_station_get_config(&stconf); wifi_station_get_config(&stconf);
os_strcpy(buff, "Unknown"); os_strcpy(buff, "Unknown");
@ -257,6 +257,7 @@ void ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg)
} }
} }
httpdSend(connData, buff, -1); httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
} }

@ -4,7 +4,7 @@
#include "httpd.h" #include "httpd.h"
int cgiWiFiScan(HttpdConnData *connData); int cgiWiFiScan(HttpdConnData *connData);
void tplWlan(HttpdConnData *connData, char *token, void **arg); int tplWlan(HttpdConnData *connData, char *token, void **arg);
int cgiWiFi(HttpdConnData *connData); int cgiWiFi(HttpdConnData *connData);
int cgiWiFiConnect(HttpdConnData *connData); int cgiWiFiConnect(HttpdConnData *connData);
int cgiWifiSetMode(HttpdConnData *connData); int cgiWifiSetMode(HttpdConnData *connData);

@ -30,7 +30,7 @@ Esp8266 http server - core routines
//Max amount of connections //Max amount of connections
#define MAX_CONN 8 #define MAX_CONN 8
//Max post buffer len //Max post buffer len
#define MAX_POST 1460 #define MAX_POST 1024
//Max send buffer len //Max send buffer len
#define MAX_SENDBUFF_LEN 2048 #define MAX_SENDBUFF_LEN 2048
@ -42,7 +42,6 @@ static HttpdBuiltInUrl *builtInUrls;
struct HttpdPriv { struct HttpdPriv {
char head[MAX_HEAD_LEN]; char head[MAX_HEAD_LEN];
int headPos; int headPos;
int postPos;
char *sendBuff; char *sendBuff;
int sendBuffLen; int sendBuffLen;
}; };
@ -287,21 +286,20 @@ static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nServer: esp8266
//This is called when the headers have been received and the connection is ready to send //This is called when the headers have been received and the connection is ready to send
//the result headers and data. //the result headers and data.
static void ICACHE_FLASH_ATTR httpdSendResp(HttpdConnData *conn) { static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) {
int r; int r;
r=conn->cgi(conn); r=conn->cgi(conn);
if (r!=HTTPD_CGI_NOTFOUND) { if (r!=HTTPD_CGI_NOTFOUND) {
if (r==HTTPD_CGI_DONE){ if (r==HTTPD_CGI_DONE) conn->cgi=NULL; //If cgi finishes immediately: mark conn for destruction.
conn->cgi=NULL; //If cgi finishes immediately: mark conn for destruction. xmitSendBuff(conn);
xmitSendBuff(conn); }else{
} //Can't find :/
return; os_printf("%s not found. 404!\n", conn->url);
httpdSend(conn, httpNotFoundHeader, -1);
xmitSendBuff(conn);
conn->cgi=NULL; //mark for destruction
} }
//Can't find :/
os_printf("%s not found. 404!\n", conn->url);
httpdSend(conn, httpNotFoundHeader, -1);
conn->cgi=NULL; //mark for destruction
} }
//Parse a line of header data and modify the connection data accordingly. //Parse a line of header data and modify the connection data accordingly.
@ -355,7 +353,6 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
conn->cgiData=NULL; conn->cgiData=NULL;
conn->cgi=builtInUrls[i].cgiCb; conn->cgi=builtInUrls[i].cgiCb;
conn->cgiArg=builtInUrls[i].cgiArg; conn->cgiArg=builtInUrls[i].cgiArg;
conn->stream=builtInUrls[i].stream;
return; return;
} }
i++; i++;
@ -366,16 +363,17 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
while (h[i]!=' ') i++; while (h[i]!=' ') i++;
//Get POST data length //Get POST data length
conn->postLen=atoi(h+i+1); conn->postLen=atoi(h+i+1);
if(conn->stream){
conn->postBuff=(char*)os_malloc(MAX_POST+1); // Allocate the buffer
if(conn->postLen > MAX_POST){
// we'll stream this in in chunks
conn->postBuffSize = MAX_POST;
}else{ }else{
//Clamp if too big. Hmm, maybe we should error out instead? conn->postBuffSize = conn->postLen;
if (conn->postLen>MAX_POST) conn->postLen=MAX_POST;
os_printf("Mallocced buffer for %d bytes of post data.\n", conn->postLen);
//Alloc the memory.
conn->postBuff=(char*)os_malloc(conn->postLen+1);
} }
conn->priv->postPos=0; os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->postBuffSize);
conn->postBuff=(char*)os_malloc(conn->postBuffSize + 1);
conn->postBuffLen=0;
} else if (os_strncmp(h, "Content-Type: ", 14)==0) { } else if (os_strncmp(h, "Content-Type: ", 14)==0) {
if(os_strstr(h, "multipart/form-data")){ if(os_strstr(h, "multipart/form-data")){
// It's multipart form data so let's pull out the boundary for future use // It's multipart form data so let's pull out the boundary for future use
@ -394,7 +392,6 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
//Callback called when there's data available on a socket. //Callback called when there's data available on a socket.
static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) { static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) {
int x; int x;
int r;
char *p, *e; char *p, *e;
char sendBuff[MAX_SENDBUFF_LEN]; char sendBuff[MAX_SENDBUFF_LEN];
HttpdConnData *conn=httpdFindConnData(arg); HttpdConnData *conn=httpdFindConnData(arg);
@ -424,40 +421,23 @@ static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short
} }
//If we don't need to receive post data, we can send the response now. //If we don't need to receive post data, we can send the response now.
if (conn->postLen==0) { if (conn->postLen==0) {
httpdSendResp(conn); httpdProcessRequest(conn);
} }
} }
} else if (conn->priv->postPos!=-1 && conn->postLen!=0 && conn->priv->postPos <= conn->postLen) { } else if (conn->postLen!=0) {
//This byte is a POST byte. //This byte is a POST byte.
conn->postBuff[conn->priv->postPos++]=data[x]; conn->postBuff[conn->postBuffLen++]=data[x];
conn->postReceived++; conn->postReceived++;
if (conn->priv->postPos>=conn->postLen) { if (conn->postBuffLen >= conn->postBuffSize || conn->postReceived == conn->postLen) {
//Received post stuff. //Received a chunk of post data
conn->postBuff[conn->priv->postPos]=0; //zero-terminate conn->postBuff[conn->postBuffLen]=0; //zero-terminate, in case the cgi handler knows it can use strings
conn->postBuffLen = conn->priv->postPos; //os_printf("Post data: %s\n", conn->postBuff);
conn->priv->postPos=-1;
os_printf("Post data: %s\n", conn->postBuff);
//Send the response. //Send the response.
httpdSendResp(conn); httpdProcessRequest(conn);
break; conn->postBuffLen = 0;
} }
} }
} }
if(conn->priv->postPos > 0 && conn->stream){
conn->postBuff[conn->priv->postPos]=0; //zero-terminate
conn->postBuffLen = conn->priv->postPos;
r=conn->cgi(conn);
if (r!=HTTPD_CGI_NOTFOUND) {
if (r==HTTPD_CGI_DONE){
conn->cgi=NULL; //If cgi finishes mark conn for destruction.
xmitSendBuff(conn);
}
}
conn->priv->postPos = 0;
}else{
xmitSendBuff(conn);
}
} }
static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
@ -510,7 +490,7 @@ static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
connData[i].conn=conn; connData[i].conn=conn;
connData[i].priv->headPos=0; connData[i].priv->headPos=0;
connData[i].postBuff=NULL; connData[i].postBuff=NULL;
connData[i].priv->postPos=0; connData[i].postBuffLen=0;
connData[i].postLen=-1; connData[i].postLen=-1;
espconn_regist_recvcb(conn, httpdRecvCb); espconn_regist_recvcb(conn, httpdRecvCb);

@ -8,9 +8,8 @@
#define HTTPD_CGI_MORE 0 #define HTTPD_CGI_MORE 0
#define HTTPD_CGI_DONE 1 #define HTTPD_CGI_DONE 1
#define HTTPD_CGI_NOTDONE 2 #define HTTPD_CGI_NOTFOUND 2
#define HTTPD_CGI_NOTFOUND 3 #define HTTPD_CGI_AUTHENTICATED 3 //for now
#define HTTPD_CGI_AUTHENTICATED 4 //for now
#define GET 1 #define GET 1
#define POST 2 #define POST 2
@ -33,10 +32,10 @@ struct HttpdConnData {
HttpdPriv *priv; HttpdPriv *priv;
cgiSendCallback cgi; cgiSendCallback cgi;
int postLen; int postLen;
int postBuffLen; int postBuffSize; // The maximum length of the post buffer
int postReceived; int postBuffLen; // The amount of bytes in the current post buffer
int postReceived; // The total amount of bytes received so far
char *postBuff; char *postBuff;
int stream;
}; };
//A struct describing an url. This is the main struct that's used to send different URL requests to //A struct describing an url. This is the main struct that's used to send different URL requests to
@ -45,7 +44,6 @@ typedef struct {
const char *url; const char *url;
cgiSendCallback cgiCb; cgiSendCallback cgiCb;
const void *cgiArg; const void *cgiArg;
int stream;
} HttpdBuiltInUrl; } HttpdBuiltInUrl;
int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData); int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData);

@ -50,27 +50,27 @@ general ones. Authorization things (like authBasic) act as a 'barrier' and
should be placed above the URLs they protect. should be placed above the URLs they protect.
*/ */
HttpdBuiltInUrl builtInUrls[]={ HttpdBuiltInUrl builtInUrls[]={
{"/", cgiRedirect, "/index.tpl", FALSE}, {"/", cgiRedirect, "/index.tpl"},
{"/flash.bin", cgiReadFlash, NULL, FALSE}, {"/flash.bin", cgiReadFlash, NULL},
{"/led.tpl", cgiEspFsTemplate, tplLed, FALSE}, {"/led.tpl", cgiEspFsTemplate, tplLed},
{"/index.tpl", cgiEspFsTemplate, tplCounter, FALSE}, {"/index.tpl", cgiEspFsTemplate, tplCounter},
{"/led.cgi", cgiLed, NULL, FALSE}, {"/led.cgi", cgiLed, NULL},
{"/updateweb.cgi", updateWeb, NULL, TRUE}, {"/updateweb.cgi", updateWeb, NULL},
//Routines to make the /wifi URL and everything beneath it work. //Routines to make the /wifi URL and everything beneath it work.
//Enable the line below to protect the WiFi configuration with an username/password combo. //Enable the line below to protect the WiFi configuration with an username/password combo.
// {"/wifi/*", authBasic, myPassFn, FALSE}, // {"/wifi/*", authBasic, myPassFn},
{"/wifi", cgiRedirect, "/wifi/wifi.tpl", FALSE}, {"/wifi", cgiRedirect, "/wifi/wifi.tpl"},
{"/wifi/", cgiRedirect, "/wifi/wifi.tpl", FALSE}, {"/wifi/", cgiRedirect, "/wifi/wifi.tpl"},
{"/wifi/wifiscan.cgi", cgiWiFiScan, NULL, FALSE}, {"/wifi/wifiscan.cgi", cgiWiFiScan, NULL},
{"/wifi/wifi.tpl", cgiEspFsTemplate, tplWlan, FALSE}, {"/wifi/wifi.tpl", cgiEspFsTemplate, tplWlan},
{"/wifi/connect.cgi", cgiWiFiConnect, NULL, FALSE}, {"/wifi/connect.cgi", cgiWiFiConnect, NULL},
{"/wifi/setmode.cgi", cgiWifiSetMode, NULL, FALSE}, {"/wifi/setmode.cgi", cgiWifiSetMode, NULL},
{"*", cgiEspFsHook, NULL, FALSE}, //Catch-all cgi function for the filesystem {"*", cgiEspFsHook, NULL}, //Catch-all cgi function for the filesystem
{NULL, NULL, NULL, FALSE} {NULL, NULL, NULL}
}; };

Loading…
Cancel
Save