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/httpParser.c b/Internet/httpServer/httpParser.c index 3d353e3..aa05f65 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,13 @@ void find_http_uri_type( */ void parse_http_request( st_http_request * request, /**< request to be returned */ - uint8_t * buf /**< pointer to be parsed */ + uint8_t * buf, /**< pointer to be parsed */ + size_t buf_len ) { char * nexttok; nexttok = strtok((char*)buf," "); - if(!nexttok) + if(nexttok == NULL) { request->METHOD = METHOD_ERR; return; @@ -163,7 +165,39 @@ 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 --- + if(request->METHOD == METHOD_POST) { + char *cl = strstr((char*)nexttok, "Content-Length:"); + if(cl) { + cl += strlen("Content-Length:"); + while(*cl == ' ') cl++; + request->post_content_length = atoi(cl); + } else { + request->post_content_length = 0; + } + char *body = strstr((char*)nexttok, "\r\n\r\n"); + 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; + } + } } #ifdef _OLD_ diff --git a/Internet/httpServer/httpParser.h b/Internet/httpServer/httpParser.h index b64be68..d785ff9 100644 --- a/Internet/httpServer/httpParser.h +++ b/Internet/httpServer/httpParser.h @@ -125,19 +125,23 @@ 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. */ + 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 *, 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 d98c482..c477500 100644 --- a/Internet/httpServer/httpServer.c +++ b/Internet/httpServer/httpServer.c @@ -9,18 +9,11 @@ #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 -#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 */ @@ -37,11 +30,10 @@ 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_ -FIL fs; // FatFs: File object FRESULT fr; // FatFs: File function return code #endif @@ -88,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; @@ -135,6 +127,7 @@ void httpServer_run(uint8_t seqnum) switch(getSn_SR(s)) { case SOCK_ESTABLISHED: + { // Interrupt clear if(getSn_IR(s) & Sn_IR_CON) { @@ -145,23 +138,26 @@ void httpServer_run(uint8_t seqnum) switch(HTTPSock_Status[seqnum].sock_status) { - case STATE_HTTP_IDLE : - if ((len = getSn_RX_RSR(s)) > 0) + 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, 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); 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 @@ -180,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); @@ -194,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 @@ -206,21 +264,22 @@ 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].file_status.fil); // Close the file handle +#endif #ifdef _USE_WATCHDOG_ HTTPServer_WDT_Reset(); #endif http_disconnect(s); - break; + break;} default : 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 @@ -230,6 +289,13 @@ void httpServer_run(uint8_t seqnum) case SOCK_CLOSED: #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; +#ifdef _USE_SDCARD_ + 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 */ { @@ -238,11 +304,12 @@ void httpServer_run(uint8_t seqnum) #endif } break; - + } case SOCK_INIT: + { listen(s); break; - + } case SOCK_LISTEN: break; @@ -314,7 +381,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; @@ -325,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) @@ -367,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 @@ -401,7 +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 - fr = f_read(&fs, &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; @@ -452,9 +520,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 } @@ -530,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); } @@ -553,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(&fs, (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 = fs.fsize; - 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_ @@ -607,23 +675,68 @@ 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_ + 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); +#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_ - 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 dcd0b00..4977949 100644 --- a/Internet/httpServer/httpServer.h +++ b/Internet/httpServer/httpServer.h @@ -15,12 +15,20 @@ 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" /* 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 @@ -41,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 @@ -67,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; @@ -75,6 +93,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_ + file_sts_t file_status; + #endif }st_http_socket; // Web content structure for file in code flash memory