From 92bb77784a8b9b00ced33da28ed1749dcf6232ed Mon Sep 17 00:00:00 2001 From: Ben Pirt Date: Fri, 6 Mar 2015 17:28:47 +0000 Subject: [PATCH] WIP - add a handler which will take a file upload and update the espfs image Currently this is processing the form/multipart data but not doing the writing to flash --- user/cgi.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++- user/httpd.h | 1 + 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/user/cgi.c b/user/cgi.c index d0ce1d3..e0c580f 100644 --- a/user/cgi.c +++ b/user/cgi.c @@ -102,9 +102,42 @@ int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) { if (*pos>=0x40200000+(512*1024)) return HTTPD_CGI_DONE; else return HTTPD_CGI_MORE; } +#define LOOKING_FOR_SECTION 1 +#define CHECKING_HEADERS 2 +#define IN_DATA 3 + +typedef struct updateState_t { + char delimiter[61]; + int step; +} updateState_t; + +char* bin_strstr(char *haystack, char *needle, int haystackLen, int needleLen){ + if(needleLen < 0){ + needleLen = strlen(needle); + } + char * end = haystack + haystackLen; + for(; haystack < end; haystack++){ + if(*haystack == *needle){ + int match = true; + for(int i = 1; i< needleLen; i++){ + if(*(needle + i) != *(haystack + i)){ + match = false; + break; + } + } + if(match){ + return haystack; + } + } + } + return NULL; +} + //Cgi to allow user to upload a new espfs image int ICACHE_FLASH_ATTR updateWeb(HttpdConnData *connData) { + os_printf("data size : %d\r\n", connData->postBuffLen); + updateState_t *state; if (connData->conn==NULL) { //Connection aborted. Clean up. return HTTPD_CGI_DONE; @@ -115,11 +148,88 @@ int ICACHE_FLASH_ATTR updateWeb(HttpdConnData *connData) { httpdEndHeaders(connData); httpdSend(connData, "
", 135); }else if(connData->requestType == POST){ + if(connData->postReceived == connData->postBuffLen){ + //it's the first time this handler has been called for this request + connData->cgiPrivData = (int*)os_malloc(sizeof(updateState_t)); + state = connData->cgiPrivData; + state->step = LOOKING_FOR_SECTION; + }else{ + state = connData->cgiPrivData; + } + + char *b; + char *p; + char * end = connData->postBuff + connData->postBuffLen; + for(b = connData->postBuff; b < end; b++){ + if(state->step == LOOKING_FOR_SECTION){ + if((p = bin_strstr(b, connData->multipartBoundary, connData->postBuffLen - (b - connData->postBuff), -1)) != NULL){ + os_printf("Found section\r\n"); + // We've found one of the sections, now make sure it's the file + b = p + strlen(connData->multipartBoundary) + 2; + state->step = CHECKING_HEADERS; + }else{ + os_printf("Not Found section\r\n"); + break; + } + } + + if(state->step == CHECKING_HEADERS){ + //os_printf("next data: %s\n", b); + if(!os_strncmp(b, "Content-Disposition: form-data", 30)){ + os_printf("Correct header\r\n"); + // It's the Content-Disposition header + // Find the end of the line + p = os_strstr(b, "\r\n"); + // turn the end of the line into a string end so we can search within the line + *p = 0; + if(os_strstr(b, "name=\"file\"") != NULL){ + os_printf("Correct file\r\n"); + b = p + 2; + // it's the correct section, skip to the data + if((p = os_strstr(b, "\r\n\r\n")) != NULL){ + os_printf("Skipping to data\r\n"); + b = p + 4; + state->step = IN_DATA; + }else{ + os_printf("Couldn't find line endings\r\n"); + os_printf("data: %s\n", b); + return HTTPD_CGI_DONE; + } + }else{ + // it's the wrong section, skip to the next boundary + b = p + 1; + state->step = LOOKING_FOR_SECTION; + } + }else{ + // Skip to the next header + p = os_strstr(b, "\r\n"); + b = p + 2; + } + } + + if(state->step == IN_DATA){ + //os_printf("In data\r\n"); + // Make sure it doesn't contain the boundary, but we can't rely on there being no zeroes so can't use strstr + if((p = bin_strstr(b, connData->multipartBoundary, connData->postBuffLen - (b - connData->postBuff), -1)) == NULL){ + // all of the data is file data + }else{ + if(b < (p - 2)){ // -2 bytes for the \r\n + // This is a byte that's part of the file + os_printf("%c", *b); + }else{ + os_printf("\r\nComplete\r\n"); + } + } + } + } + /* os_printf("postReceived: %d\r\n", connData->postReceived); os_printf("postLen : %d\r\n", connData->postLen); - os_printf("data size : %d\r\n", strlen(connData->postBuff)); + os_printf("data size : %d\r\n", connData->postBuffLen); + */ if(connData->postReceived >= connData->postLen){ httpdStartResponse(connData, 204); + if (connData->cgiPrivData!=NULL) os_free(connData->cgiPrivData); return HTTPD_CGI_DONE; }else{ return HTTPD_CGI_NOTDONE; diff --git a/user/httpd.h b/user/httpd.h index 082f4ca..0829ea3 100644 --- a/user/httpd.h +++ b/user/httpd.h @@ -28,6 +28,7 @@ struct HttpdConnData { char *getArgs; const void *cgiArg; void *cgiData; + void *cgiPrivData; // Used for streaming handlers storing state between requests char *multipartBoundary; HttpdPriv *priv; cgiSendCallback cgi;