From 6aeb8ae1e9b0486ad450220333b2a5a91637009b Mon Sep 17 00:00:00 2001 From: Cami Date: Mon, 28 Jul 2025 15:52:15 +0200 Subject: [PATCH 1/3] Add support for SD card file handling in HTTP server Fixed fragmented response for files > 2kB Fixed parallel access to files if using multiple sockets --- Internet/TFTP/tftp.h | 1 + Internet/httpServer/httpServer.c | 32 +++++++++++++++++--------------- Internet/httpServer/httpServer.h | 8 +++++++- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Internet/TFTP/tftp.h b/Internet/TFTP/tftp.h index a1cb890..805602c 100644 --- a/Internet/TFTP/tftp.h +++ b/Internet/TFTP/tftp.h @@ -12,6 +12,7 @@ extern "C" { #endif #include +#include #define F_APP_TFTP #define __TFTP_DEBUG__ diff --git a/Internet/httpServer/httpServer.c b/Internet/httpServer/httpServer.c index d98c482..e69b4aa 100644 --- a/Internet/httpServer/httpServer.c +++ b/Internet/httpServer/httpServer.c @@ -9,9 +9,7 @@ #include "httpParser.h" #include "httpUtil.h" -#ifdef _USE_SDCARD_ -#include "ff.h" // header file for FatFs library (FAT file system) -#endif + #ifndef DATA_BUF_SIZE #define DATA_BUF_SIZE 2048 @@ -41,7 +39,6 @@ st_http_socket HTTPSock_Status[_WIZCHIP_SOCK_NUM_] = { {STATE_HTTP_IDLE, }, }; httpServer_webContent web_content[MAX_CONTENT_CALLBACK]; #ifdef _USE_SDCARD_ -FIL fs; // FatFs: File object FRESULT fr; // FatFs: File function return code #endif @@ -206,9 +203,9 @@ void httpServer_run(uint8_t seqnum) HTTPSock_Status[seqnum].file_start = 0; HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; -//#ifdef _USE_SDCARD_ -// f_close(&fs); -//#endif +#ifdef _USE_SDCARD_ + f_close(&HTTPSock_Status[seqnum].fil); // Close the file handle +#endif #ifdef _USE_WATCHDOG_ HTTPServer_WDT_Reset(); #endif @@ -231,6 +228,10 @@ void httpServer_run(uint8_t seqnum) #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : CLOSED\r\n", s); #endif + HTTPSock_Status[seqnum].file_len = 0; + HTTPSock_Status[seqnum].file_offset = 0; + HTTPSock_Status[seqnum].file_start = 0; + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; if(socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */ { #ifdef _HTTPSERVER_DEBUG_ @@ -314,7 +315,7 @@ static void send_http_response_body(uint8_t s, uint8_t * uri_name, uint8_t * buf uint8_t flag_datasend_end = 0; #ifdef _USE_SDCARD_ - uint16_t blocklen; + UINT blocklen; #endif #ifdef _USE_FLASH_ uint32_t addr = 0; @@ -401,7 +402,8 @@ static void send_http_response_body(uint8_t s, uint8_t * uri_name, uint8_t * buf else if(HTTPSock_Status[get_seqnum].storage_type == SDCARD) { // Data read from SD Card - fr = f_read(&fs, &buf[0], send_len, (void *)&blocklen); + f_lseek(&HTTPSock_Status[get_seqnum].fil, HTTPSock_Status[get_seqnum].file_offset); + fr = f_read(&HTTPSock_Status[get_seqnum].fil, &buf[0], send_len, (void *)&blocklen); if(fr != FR_OK) { send_len = 0; @@ -452,9 +454,9 @@ static void send_http_response_body(uint8_t s, uint8_t * uri_name, uint8_t * buf } // ## 20141219 Eric added, for 'File object structure' (fs) allocation reduced (8 -> 1) -#ifdef _USE_SDCARD_ - f_close(&fs); -#endif +//#ifdef _USE_SDCARD_ +// f_close(&fs); +//#endif // ## 20141219 added end } @@ -553,12 +555,12 @@ static void http_process_handler(uint8_t s, st_http_request * p_http_request) #ifdef _HTTPSERVER_DEBUG_ printf("\r\n> HTTPSocket[%d] : Searching the requested content\r\n", s); #endif - if((fr = f_open(&fs, (const char *)uri_name, FA_READ)) == 0) + if((fr = f_open(&HTTPSock_Status[get_seqnum].fil, (const char *)uri_name, FA_READ)) == 0) { content_found = 1; // file open succeed - file_len = fs.fsize; - content_addr = fs.sclust; + file_len = HTTPSock_Status[get_seqnum].fil.obj.objsize; //file_len = fs.fsize; + content_addr = HTTPSock_Status[get_seqnum].fil.obj.sclust; //content_addr = fs.sclust; HTTPSock_Status[get_seqnum].storage_type = SDCARD; } #elif _USE_FLASH_ diff --git a/Internet/httpServer/httpServer.h b/Internet/httpServer/httpServer.h index dcd0b00..fca0e51 100644 --- a/Internet/httpServer/httpServer.h +++ b/Internet/httpServer/httpServer.h @@ -20,7 +20,10 @@ extern "C" { #define MOBILE_INITIAL_WEBPAGE "mobile/index.html" /* Web Server Content Storage Select */ -//#define _USE_SDCARD_ +#define _USE_SDCARD_ +#ifdef _USE_SDCARD_ +#include "ff.h" // header file for FatFs library (FAT file system) +#endif #ifndef _USE_SDCARD_ //#define _USE_FLASH_ #endif @@ -75,6 +78,9 @@ typedef struct _st_http_socket uint32_t file_len; uint32_t file_offset; // (start addr + sent size...) uint8_t storage_type; // Storage type; Code flash, SDcard, Data flash ... + #ifdef _USE_SDCARD_ + FIL fil; // File handle for SD card + #endif }st_http_socket; // Web content structure for file in code flash memory From 587defe74f0041831bcb5d23302e44dfb8c3623e Mon Sep 17 00:00:00 2001 From: Cami Date: Mon, 11 Aug 2025 13:51:22 +0200 Subject: [PATCH 2/3] Tentantivo di gestione POST, garbage in caso di post frammentati --- Internet/httpServer/httpParser.c | 28 +++++++++++++-- Internet/httpServer/httpParser.h | 11 +++--- Internet/httpServer/httpServer.c | 62 ++++++++++++++++++++++++-------- 3 files changed, 81 insertions(+), 20 deletions(-) diff --git a/Internet/httpServer/httpParser.c b/Internet/httpServer/httpParser.c index 3d353e3..16d11b4 100644 --- a/Internet/httpServer/httpParser.c +++ b/Internet/httpServer/httpParser.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "socket.h" #include "httpParser.h" @@ -126,12 +127,12 @@ void find_http_uri_type( */ void parse_http_request( st_http_request * request, /**< request to be returned */ - uint8_t * buf /**< pointer to be parsed */ + volatile uint8_t * buf /**< pointer to be parsed */ ) { char * nexttok; nexttok = strtok((char*)buf," "); - if(!nexttok) + if(nexttok == NULL) { request->METHOD = METHOD_ERR; return; @@ -164,6 +165,29 @@ void parse_http_request( return; } strcpy((char *)request->URI, nexttok); + //nexttok = strtok(NULL,"\0"); + + // --- Extract POST body and Content-Length --- + if(request->METHOD == METHOD_POST) { + char *cl = strstr((char*)nexttok, "Content-Length:"); + if(cl) { + cl += strlen("Content-Length:"); + while(*cl == ' ') cl++; + request->BODY_LENGTH = atoi(cl); + } else { + request->BODY_LENGTH = 0; + } + char *body = strstr((char*)nexttok, "\r\n\r\n"); + if(body) { + body += 4; + if(request->BODY_LENGTH > 0 && request->BODY_LENGTH < sizeof(request->BODY)) { + memcpy(request->BODY, body, request->BODY_LENGTH); + request->BODY[request->BODY_LENGTH] = 0; + } else { + request->BODY[0] = 0; + } + } + } } #ifdef _OLD_ diff --git a/Internet/httpServer/httpParser.h b/Internet/httpServer/httpParser.h index b64be68..8a9a14a 100644 --- a/Internet/httpServer/httpParser.h +++ b/Internet/httpServer/httpParser.h @@ -125,19 +125,22 @@ static const char ERROR_REQUEST_PAGE[] = "HTTP/1.1 400 OK\r\nContent-Type: text @brief Structure of HTTP REQUEST */ -//#define MAX_URI_SIZE 1461 -#define MAX_URI_SIZE 512 + +// the whole size of st_http_request must be less than DATA_BUF_SIZE (DATA_BUF_SIZE = 2048) +#define MAX_URI_SIZE 256 typedef struct _st_http_request { uint8_t METHOD; /**< request method(METHOD_GET...). */ uint8_t TYPE; /**< request type(PTYPE_HTML...). */ - uint8_t URI[MAX_URI_SIZE]; /**< request file name. */ + uint8_t URI[MAX_URI_SIZE]; /**< request file name. */ + unsigned char BODY[1500]; /**< request body. */ + size_t BODY_LENGTH; /**< request body length. */ }st_http_request; // HTTP Parsing functions void unescape_http_url(char * url); /* convert escape character to ascii */ -void parse_http_request(st_http_request *, uint8_t *); /* parse request from peer */ +void parse_http_request(st_http_request *, volatile uint8_t *); /* parse request from peer */ void find_http_uri_type(uint8_t *, uint8_t *); /* find MIME type of a file */ void make_http_response_head(char *, char, uint32_t); /* make response header */ uint8_t * get_http_param_value(char* uri, char* param_name); /* get the user-specific parameter value */ diff --git a/Internet/httpServer/httpServer.c b/Internet/httpServer/httpServer.c index e69b4aa..5c846e7 100644 --- a/Internet/httpServer/httpServer.c +++ b/Internet/httpServer/httpServer.c @@ -132,6 +132,7 @@ void httpServer_run(uint8_t seqnum) switch(getSn_SR(s)) { case SOCK_ESTABLISHED: + { // Interrupt clear if(getSn_IR(s) & Sn_IR_CON) { @@ -143,9 +144,14 @@ void httpServer_run(uint8_t seqnum) { case STATE_HTTP_IDLE : - if ((len = getSn_RX_RSR(s)) > 0) + if ((len = getSn_RX_RSR(s)) > 0) //Sn_RX_RSR indicates the data size received and saved in Socket n RX Buffer. Sn_RX_RSR does not exceed the Sn_RXBUF_SIZE { - if (len > DATA_BUF_SIZE) len = DATA_BUF_SIZE; + if (len > DATA_BUF_SIZE){ + len = DATA_BUF_SIZE; +#ifdef _HTTPSERVER_DEBUG_ + printf("> HTTPSocket[%d] : [Error] Received data length exceeds buffer size (%d)\r\n", s, DATA_BUF_SIZE); +#endif + } len = recv(s, (uint8_t *)http_request, len); *(((uint8_t *)http_request) + len) = '\0'; @@ -157,8 +163,6 @@ void httpServer_run(uint8_t seqnum) printf("\r\n"); printf("> HTTPSocket[%d] : HTTP Request received ", s); printf("from %d.%d.%d.%d : %d\r\n", destip[0], destip[1], destip[2], destip[3], destport); -#endif -#ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_REQ_DONE\r\n", s); #endif // HTTP 'response' handler; includes send_http_response_header / body function @@ -216,8 +220,9 @@ void httpServer_run(uint8_t seqnum) break; } break; - + } case SOCK_CLOSE_WAIT: + { #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : ClOSE_WAIT\r\n", s); // if a peer requests to close the current connection #endif @@ -232,6 +237,9 @@ void httpServer_run(uint8_t seqnum) HTTPSock_Status[seqnum].file_offset = 0; HTTPSock_Status[seqnum].file_start = 0; HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; +#ifdef _USE_SDCARD_ + f_close(&HTTPSock_Status[seqnum].fil); // Close the file handle +#endif if(socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */ { #ifdef _HTTPSERVER_DEBUG_ @@ -239,11 +247,12 @@ void httpServer_run(uint8_t seqnum) #endif } break; - + } case SOCK_INIT: + { listen(s); break; - + } case SOCK_LISTEN: break; @@ -609,17 +618,42 @@ static void http_process_handler(uint8_t s, st_http_request * p_http_request) break; case METHOD_POST : - mid((char *)p_http_request->URI, "/", " HTTP", (char *)uri_buf); - uri_name = uri_buf; - find_http_uri_type(&p_http_request->TYPE, uri_name); // Check file type (HTML, TEXT, GIF, JPEG are included) + mid((char *)p_http_request->URI, "/", " HTTP", (char *)uri_buf); + uri_name = uri_buf; + find_http_uri_type(&p_http_request->TYPE, uri_name); #ifdef _HTTPSERVER_DEBUG_ - printf("\r\n> HTTPSocket[%d] : HTTP Method POST\r\n", s); - printf("> HTTPSocket[%d] : Request URI = %s ", s, uri_name); - printf("Type = %d\r\n", p_http_request->TYPE); + printf("\r\n> HTTPSocket[%d] : HTTP Method POST\r\n", s); + printf("> HTTPSocket[%d] : Request URI = %s ", s, uri_name); + printf("Type = %d\r\n", p_http_request->TYPE); #endif - if(p_http_request->TYPE == PTYPE_CGI) // HTTP POST Method; CGI Process + // Check for JSON content type + if(p_http_request->TYPE == PTYPE_JSON) { +#ifdef _USE_SDCARD_ + // Save posted JSON to SD card + FRESULT fr; + FIL jsonFile; + UINT bw; + // Use URI as filename, or a fixed name like "post.json" + const char *jsonFilename = uri_name; // or "post.json"; + fr = f_open(&jsonFile, jsonFilename, FA_WRITE | FA_CREATE_ALWAYS); + if(fr == FR_OK) { + fr = f_write(&jsonFile, p_http_request->BODY, p_http_request->BODY_LENGTH, &bw); + f_close(&jsonFile); + if(fr == FR_OK && bw == p_http_request->BODY_LENGTH) { + send_http_response_header(s, PTYPE_JSON, 0, STATUS_OK); + } else { + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + } + } else { + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + } +#else + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); +#endif + } + else if(p_http_request->TYPE == PTYPE_CGI) // HTTP POST Method; CGI Process { content_found = http_post_cgi_handler(uri_name, p_http_request, http_response, &file_len); #ifdef _HTTPSERVER_DEBUG_ From 9cc52597c65e8e0fad70fa222e28c8f623ae8406 Mon Sep 17 00:00:00 2001 From: Cami Date: Sat, 16 Aug 2025 21:47:46 +0200 Subject: [PATCH 3/3] major changes to fix fragmented post to file --- Internet/httpServer/httpParser.c | 34 ++++-- Internet/httpServer/httpParser.h | 7 +- Internet/httpServer/httpServer.c | 185 ++++++++++++++++++++++--------- Internet/httpServer/httpServer.h | 17 ++- 4 files changed, 173 insertions(+), 70 deletions(-) diff --git a/Internet/httpServer/httpParser.c b/Internet/httpServer/httpParser.c index 16d11b4..aa05f65 100644 --- a/Internet/httpServer/httpParser.c +++ b/Internet/httpServer/httpParser.c @@ -127,7 +127,8 @@ void find_http_uri_type( */ void parse_http_request( st_http_request * request, /**< request to be returned */ - volatile uint8_t * buf /**< pointer to be parsed */ + uint8_t * buf, /**< pointer to be parsed */ + size_t buf_len ) { char * nexttok; @@ -164,7 +165,15 @@ void parse_http_request( request->METHOD = METHOD_ERR; return; } + + //check for uri length, if ok copy + size_t l = strlen(nexttok); + if(l >= MAX_URI_SIZE){ + request->METHOD = METHOD_ERR; + return; + } strcpy((char *)request->URI, nexttok); + //nexttok = strtok(NULL,"\0"); // --- Extract POST body and Content-Length --- @@ -173,20 +182,21 @@ void parse_http_request( if(cl) { cl += strlen("Content-Length:"); while(*cl == ' ') cl++; - request->BODY_LENGTH = atoi(cl); + request->post_content_length = atoi(cl); } else { - request->BODY_LENGTH = 0; + request->post_content_length = 0; } char *body = strstr((char*)nexttok, "\r\n\r\n"); - if(body) { - body += 4; - if(request->BODY_LENGTH > 0 && request->BODY_LENGTH < sizeof(request->BODY)) { - memcpy(request->BODY, body, request->BODY_LENGTH); - request->BODY[request->BODY_LENGTH] = 0; - } else { - request->BODY[0] = 0; - } - } + if (body) { + body += 4; + int offset = body - (char*)buf; + int available = buf_len - offset; + request->post_body_ptr = body; + request->post_body_length = (available > 0) ? available : 0; + } else { + request->post_body_ptr = NULL; + request->post_body_length = 0; + } } } diff --git a/Internet/httpServer/httpParser.h b/Internet/httpServer/httpParser.h index 8a9a14a..d785ff9 100644 --- a/Internet/httpServer/httpParser.h +++ b/Internet/httpServer/httpParser.h @@ -134,13 +134,14 @@ typedef struct _st_http_request uint8_t METHOD; /**< request method(METHOD_GET...). */ uint8_t TYPE; /**< request type(PTYPE_HTML...). */ uint8_t URI[MAX_URI_SIZE]; /**< request file name. */ - unsigned char BODY[1500]; /**< request body. */ - size_t BODY_LENGTH; /**< request body length. */ + size_t post_content_length; /**< in POST request Content-Length */ + size_t post_body_length; /**< in POST request body length */ + uint8_t * post_body_ptr; /**< in POST pointer to body */ }st_http_request; // HTTP Parsing functions void unescape_http_url(char * url); /* convert escape character to ascii */ -void parse_http_request(st_http_request *, volatile uint8_t *); /* parse request from peer */ +void parse_http_request(st_http_request *, uint8_t *, size_t); /* parse request from peer */ void find_http_uri_type(uint8_t *, uint8_t *); /* find MIME type of a file */ void make_http_response_head(char *, char, uint32_t); /* make response header */ uint8_t * get_http_param_value(char* uri, char* param_name); /* get the user-specific parameter value */ diff --git a/Internet/httpServer/httpServer.c b/Internet/httpServer/httpServer.c index 5c846e7..c477500 100644 --- a/Internet/httpServer/httpServer.c +++ b/Internet/httpServer/httpServer.c @@ -10,15 +10,10 @@ #include "httpUtil.h" - -#ifndef DATA_BUF_SIZE - #define DATA_BUF_SIZE 2048 -#endif - /***************************************************************************** * Private types/enumerations/variables ****************************************************************************/ -static uint8_t HTTPSock_Num[_WIZCHIP_SOCK_NUM_] = {0, }; +static uint8_t HTTPSock_Num[HTTP_SOCKET_MAX_NUM] = {0, }; static st_http_request * http_request; /**< Pointer to received HTTP request */ static st_http_request * parsed_http_request; /**< Pointer to parsed HTTP request */ static uint8_t * http_response; /**< Pointer to HTTP response */ @@ -35,7 +30,7 @@ uint8_t * pHTTP_TX; uint8_t * pHTTP_RX; volatile uint32_t httpServer_tick_1s = 0; -st_http_socket HTTPSock_Status[_WIZCHIP_SOCK_NUM_] = { {STATE_HTTP_IDLE, }, }; +st_http_socket HTTPSock_Status[HTTP_SOCKET_MAX_NUM] = { {STATE_HTTP_IDLE, }, }; httpServer_webContent web_content[MAX_CONTENT_CALLBACK]; #ifdef _USE_SDCARD_ @@ -85,7 +80,7 @@ static int8_t getHTTPSequenceNum(uint8_t socket) { uint8_t i; - for(i = 0; i < _WIZCHIP_SOCK_NUM_; i++) + for(i = 0; i < HTTP_SOCKET_MAX_NUM; i++) if(HTTPSock_Num[i] == socket) return i; return -1; @@ -143,20 +138,20 @@ void httpServer_run(uint8_t seqnum) switch(HTTPSock_Status[seqnum].sock_status) { - case STATE_HTTP_IDLE : + case STATE_HTTP_IDLE :{ if ((len = getSn_RX_RSR(s)) > 0) //Sn_RX_RSR indicates the data size received and saved in Socket n RX Buffer. Sn_RX_RSR does not exceed the Sn_RXBUF_SIZE { - if (len > DATA_BUF_SIZE){ - len = DATA_BUF_SIZE; + if (len > HTTP_RXTX_BUF_SIZE){ + len = HTTP_RXTX_BUF_SIZE; #ifdef _HTTPSERVER_DEBUG_ - printf("> HTTPSocket[%d] : [Error] Received data length exceeds buffer size (%d)\r\n", s, DATA_BUF_SIZE); + printf("> HTTPSocket[%d] : [Error] Received data length exceeds buffer size (%d)\r\n", s, HTTP_RXTX_BUF_SIZE); #endif } len = recv(s, (uint8_t *)http_request, len); *(((uint8_t *)http_request) + len) = '\0'; - parse_http_request(parsed_http_request, (uint8_t *)http_request); + parse_http_request(parsed_http_request, (uint8_t *)http_request, len); #ifdef _HTTPSERVER_DEBUG_ getSn_DIPR(s, destip); destport = getSn_DPORT(s); @@ -181,12 +176,13 @@ void httpServer_run(uint8_t seqnum) } } - if(HTTPSock_Status[seqnum].file_len > 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_INPROC; + if(parsed_http_request->METHOD == METHOD_POST) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_POST_INPROC; + else if(HTTPSock_Status[seqnum].file_len > 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_INPROC; else HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; // Send the 'HTTP response' end } - break; + break;} - case STATE_HTTP_RES_INPROC : + case STATE_HTTP_RES_INPROC :{ /* Repeat: Send the remain parts of HTTP responses */ #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_INPROC\r\n", s); @@ -195,9 +191,70 @@ void httpServer_run(uint8_t seqnum) send_http_response_body(s, 0, http_response, 0, 0); if(HTTPSock_Status[seqnum].file_len == 0) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + break;} + + case STATE_HTTP_POST_INPROC :{ + len = getSn_RX_RSR(s); + if(len > HTTP_RXTX_BUF_SIZE){ + len = HTTP_RXTX_BUF_SIZE; +#ifdef _HTTPSERVER_DEBUG_ + printf("> HTTPSocket[%d] : [Error] Received data length exceeds buffer size (%d)\r\n", s, HTTP_RXTX_BUF_SIZE); +#endif + } + if(len > 0) + { + len = recv(s, (uint8_t *)http_request, len); + + // Find POST body in buffer (assume it starts after \r\n\r\n) + char *body = strstr((char *)http_request, "\r\n\r\n"); + int body_offset = 0; + if(body) { + body += 4; + body_offset = body - (char *)http_request; + } else { + // If not found, treat whole buffer as body + body = (char *)http_request; + body_offset = 0; + } + + file_sts_t *pst = &HTTPSock_Status[seqnum].file_status; + FRESULT fr; + UINT bw; + + // file should be open at this point + if (!pst->file_opened) { + // File should be open at this point; handle error + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + break; + } + + // Write fragment to file + fr = f_write(&pst->fil, body, len - body_offset, &bw); + pst->received_len += bw; + + // If error or mismatch, abort + if (fr != FR_OK || bw != (len - body_offset)) { + f_close(&pst->fil); + pst->file_opened = 0; + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + break; + } + + // If all data received, close file and send response + if (pst->expected_len > 0 && pst->received_len >= pst->expected_len) { + f_close(&pst->fil); + pst->file_opened = 0; + send_http_response_header(s, PTYPE_JSON, 0, STATUS_OK); + HTTPSock_Status[seqnum].sock_status = STATE_HTTP_RES_DONE; + } + // else: stay in STATE_HTTP_POST_INPROC and wait for more data + } break; + } - case STATE_HTTP_RES_DONE : + case STATE_HTTP_RES_DONE :{ #ifdef _HTTPSERVER_DEBUG_ printf("> HTTPSocket[%d] : [State] STATE_HTTP_RES_DONE\r\n", s); #endif @@ -208,13 +265,13 @@ void httpServer_run(uint8_t seqnum) HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; #ifdef _USE_SDCARD_ - f_close(&HTTPSock_Status[seqnum].fil); // Close the file handle + f_close(&HTTPSock_Status[seqnum].file_status.fil); // Close the file handle #endif #ifdef _USE_WATCHDOG_ HTTPServer_WDT_Reset(); #endif http_disconnect(s); - break; + break;} default : break; @@ -238,7 +295,7 @@ void httpServer_run(uint8_t seqnum) HTTPSock_Status[seqnum].file_start = 0; HTTPSock_Status[seqnum].sock_status = STATE_HTTP_IDLE; #ifdef _USE_SDCARD_ - f_close(&HTTPSock_Status[seqnum].fil); // Close the file handle + f_close(&HTTPSock_Status[seqnum].file_status.fil); // Close the file handle #endif if(socket(s, Sn_MR_TCP, HTTP_SERVER_PORT, 0x00) == s) /* Reinitialize the socket */ { @@ -335,11 +392,11 @@ static void send_http_response_body(uint8_t s, uint8_t * uri_name, uint8_t * buf // Send the HTTP Response 'body'; requested file if(!HTTPSock_Status[get_seqnum].file_len) // ### Send HTTP response body: First part ### { - if (file_len > DATA_BUF_SIZE - 1) + if (file_len > HTTP_RXTX_BUF_SIZE - 1) { HTTPSock_Status[get_seqnum].file_start = start_addr; HTTPSock_Status[get_seqnum].file_len = file_len; - send_len = DATA_BUF_SIZE - 1; + send_len = HTTP_RXTX_BUF_SIZE - 1; ///////////////////////////////////////////////////////////////////////////////////////////////// // ## 20141219 Eric added, for 'File object structure' (fs) allocation reduced (8 -> 1) @@ -377,9 +434,9 @@ static void send_http_response_body(uint8_t s, uint8_t * uri_name, uint8_t * buf #endif send_len = HTTPSock_Status[get_seqnum].file_len - HTTPSock_Status[get_seqnum].file_offset; - if(send_len > DATA_BUF_SIZE - 1) + if(send_len > HTTP_RXTX_BUF_SIZE - 1) { - send_len = DATA_BUF_SIZE - 1; + send_len = HTTP_RXTX_BUF_SIZE - 1; //HTTPSock_Status[get_seqnum]->file_offset += send_len; } else @@ -411,8 +468,8 @@ static void send_http_response_body(uint8_t s, uint8_t * uri_name, uint8_t * buf else if(HTTPSock_Status[get_seqnum].storage_type == SDCARD) { // Data read from SD Card - f_lseek(&HTTPSock_Status[get_seqnum].fil, HTTPSock_Status[get_seqnum].file_offset); - fr = f_read(&HTTPSock_Status[get_seqnum].fil, &buf[0], send_len, (void *)&blocklen); + f_lseek(&HTTPSock_Status[get_seqnum].file_status.fil, HTTPSock_Status[get_seqnum].file_offset); + fr = f_read(&HTTPSock_Status[get_seqnum].file_status.fil, &buf[0], send_len, (void *)&blocklen); if(fr != FR_OK) { send_len = 0; @@ -541,7 +598,7 @@ static void http_process_handler(uint8_t s, st_http_request * p_http_request) if(p_http_request->TYPE == PTYPE_CGI) { content_found = http_get_cgi_handler(uri_name, pHTTP_TX, &file_len); - if(content_found && (file_len <= (DATA_BUF_SIZE-(strlen(RES_CGIHEAD_OK)+8)))) + if(content_found && (file_len <= (HTTP_RXTX_BUF_SIZE-(strlen(RES_CGIHEAD_OK)+8)))) { send_http_response_cgi(s, http_response, pHTTP_TX, (uint16_t)file_len); } @@ -564,12 +621,12 @@ static void http_process_handler(uint8_t s, st_http_request * p_http_request) #ifdef _HTTPSERVER_DEBUG_ printf("\r\n> HTTPSocket[%d] : Searching the requested content\r\n", s); #endif - if((fr = f_open(&HTTPSock_Status[get_seqnum].fil, (const char *)uri_name, FA_READ)) == 0) + if((fr = f_open(&HTTPSock_Status[get_seqnum].file_status.fil, (const char *)uri_name, FA_READ)) == 0) { content_found = 1; // file open succeed - file_len = HTTPSock_Status[get_seqnum].fil.obj.objsize; //file_len = fs.fsize; - content_addr = HTTPSock_Status[get_seqnum].fil.obj.sclust; //content_addr = fs.sclust; + file_len = HTTPSock_Status[get_seqnum].file_status.fil.obj.objsize; //file_len = fs.fsize; + content_addr = HTTPSock_Status[get_seqnum].file_status.fil.obj.sclust; //content_addr = fs.sclust; HTTPSock_Status[get_seqnum].storage_type = SDCARD; } #elif _USE_FLASH_ @@ -628,38 +685,58 @@ static void http_process_handler(uint8_t s, st_http_request * p_http_request) printf("Type = %d\r\n", p_http_request->TYPE); #endif - // Check for JSON content type + // Check for JSON content type if(p_http_request->TYPE == PTYPE_JSON) { #ifdef _USE_SDCARD_ - // Save posted JSON to SD card - FRESULT fr; - FIL jsonFile; - UINT bw; - // Use URI as filename, or a fixed name like "post.json" - const char *jsonFilename = uri_name; // or "post.json"; - fr = f_open(&jsonFile, jsonFilename, FA_WRITE | FA_CREATE_ALWAYS); - if(fr == FR_OK) { - fr = f_write(&jsonFile, p_http_request->BODY, p_http_request->BODY_LENGTH, &bw); - f_close(&jsonFile); - if(fr == FR_OK && bw == p_http_request->BODY_LENGTH) { - send_http_response_header(s, PTYPE_JSON, 0, STATUS_OK); - } else { - send_http_response_header(s, 0, 0, STATUS_BAD_REQ); - } - } else { - send_http_response_header(s, 0, 0, STATUS_BAD_REQ); - } + file_sts_t *pst = &HTTPSock_Status[get_seqnum].file_status; + FRESULT fr; + UINT bw; + + // On first fragment, open file and initialize state + if (!pst->file_opened) { + const char *jsonFilename = uri_name; // or "post.json"; + fr = f_open(&pst->fil, jsonFilename, FA_WRITE | FA_CREATE_ALWAYS); + if (fr != FR_OK) { + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + break; + } + pst->expected_len = p_http_request->post_content_length; // Set from Content-Length header + pst->received_len = 0; + pst->file_opened = 1; + } + + // Append this fragment + if (p_http_request->post_body_ptr && p_http_request->post_body_length > 0) { + fr = f_write(&pst->fil, p_http_request->post_body_ptr, p_http_request->post_body_length, &bw); + pst->received_len += bw; + + // If error or mismatch, abort + if (fr != FR_OK || bw != p_http_request->post_content_length) { + f_close(&pst->fil); + pst->file_opened = 0; + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + break; + } + } + + // If all data received, close file and send response + if (pst->received_len >= pst->expected_len) { + f_close(&pst->fil); + pst->file_opened = 0; + send_http_response_header(s, PTYPE_JSON, 0, STATUS_OK); + } + // else: wait for more data in next call #else - send_http_response_header(s, 0, 0, STATUS_BAD_REQ); + send_http_response_header(s, 0, 0, STATUS_BAD_REQ); #endif - } - else if(p_http_request->TYPE == PTYPE_CGI) // HTTP POST Method; CGI Process + } + else if(p_http_request->TYPE == PTYPE_CGI) // HTTP POST Method; CGI Process { content_found = http_post_cgi_handler(uri_name, p_http_request, http_response, &file_len); #ifdef _HTTPSERVER_DEBUG_ - printf("> HTTPSocket[%d] : [CGI: %s] / Response len [ %ld ]byte\r\n", s, content_found?"Content found":"Content not found", file_len); + printf("> HTTPSocket[%d] : [CGI: %s] / Response len [ %ld ]byte\r\n", s, content_found?"Content found":"Content not found", file_len); #endif - if(content_found && (file_len <= (DATA_BUF_SIZE-(strlen(RES_CGIHEAD_OK)+8)))) + if(content_found && (file_len <= (HTTP_RXTX_BUF_SIZE-(strlen(RES_CGIHEAD_OK)+8)))) { send_http_response_cgi(s, pHTTP_TX, http_response, (uint16_t)file_len); diff --git a/Internet/httpServer/httpServer.h b/Internet/httpServer/httpServer.h index fca0e51..4977949 100644 --- a/Internet/httpServer/httpServer.h +++ b/Internet/httpServer/httpServer.h @@ -15,6 +15,11 @@ extern "C" { // HTTP Server debug message enable #define _HTTPSERVER_DEBUG_ +// Number of sockets used by HTTP Server +#define HTTP_SOCKET_MAX_NUM 3 +//Size of RX/TX buffers +#define HTTP_RXTX_BUF_SIZE 2048 + #define INITIAL_WEBPAGE "index.html" #define M_INITIAL_WEBPAGE "m/index.html" #define MOBILE_INITIAL_WEBPAGE "mobile/index.html" @@ -44,6 +49,8 @@ extern "C" { #define STATE_HTTP_REQ_DONE 2 /* The end of HTTP request parse */ #define STATE_HTTP_RES_INPROC 3 /* Sending the HTTP response to HTTP client (in progress) */ #define STATE_HTTP_RES_DONE 4 /* The end of HTTP response send (HTTP transaction ended) */ +#define STATE_HTTP_POST_INPROC 5 /* Receiving HTTP POST data (in progress) */ + /********************************************* * HTTP Simple Return Value @@ -70,6 +77,14 @@ typedef enum DATAFLASH ///< External data flash memory }StorageType; +typedef struct{ + FIL fil; // File handle for SD card + int file_opened; + size_t expected_len; + size_t received_len; +}file_sts_t; + + typedef struct _st_http_socket { uint8_t sock_status; @@ -79,7 +94,7 @@ typedef struct _st_http_socket uint32_t file_offset; // (start addr + sent size...) uint8_t storage_type; // Storage type; Code flash, SDcard, Data flash ... #ifdef _USE_SDCARD_ - FIL fil; // File handle for SD card + file_sts_t file_status; #endif }st_http_socket;