Simple HTTP Server with one page index.html stored inside MBED as char vector and javascript to update a table content
Fork of HTTP_SERVER by
Revision 0:cc483bea4fe3, committed 2016-02-16
- Comitter:
- aktk
- Date:
- Tue Feb 16 10:59:31 2016 +0000
- Child:
- 1:3a1fe94c6e42
- Commit message:
- add comment
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTP_SERVER.cpp Tue Feb 16 10:59:31 2016 +0000 @@ -0,0 +1,208 @@ +#include "HTTP_SERVER.h" +#define DEBUG +HttpServer::HttpServer() +{ + keep_alive = (false); + listening_flag = (false); + req_buf[0] = '\0'; +} + +HttpServer::~HttpServer() +{ +} + +bool HttpServer::init() +{ + +// Ethernet Initialization + if(eth.init()) { + printf("Error!@EthernetInterface::init()\r\n"); + return false; + } + // Ethernet Connecting setup + if(eth.connect()) { + printf("Error!@EthernetInterface::connect()\r\n"); + return false; + } else { + printf("IP Address is %s\r\n", eth.getIPAddress()); + } + // TCP Socket setup + // To open Server-side PORT + if(tcpsvr.bind(TCP_PORT)< 0) { + printf("Error!@TCPSocketServer::bind()\r\n"); + return false; + } else { + printf("TCP Server has bounden!\r\n"); + } + // Server start listening Request from a web browser. + if(tcpsvr.listen(1) < 0) { + printf("tcp server listen failed.\r\n"); + return false; + } else { + listening_flag = true; + printf("tcp server is listening...\r\n"); + } + + return true; +} + +bool HttpServer::run() +{ + DigitalOut led1(LED1); + DigitalOut led2(LED1); + + while (listening_flag) { + led1 = true; + // blocking mode (never timeout) + // waiting client connection + printf("\r\nwait connection\r\n"); + if(tcpsvr.accept(tcpcon) < 0) { + printf("failed to accept connection.\r\n"); + return -1; + } else { + printf("connection success!\r\nIP: %s\r\n",tcpcon.get_address()); + led2 = true; + } + //while(client.is_connected()) { + while(tcpcon.is_connected()) { +#ifdef DEBUG + printf("being connected\r\n"); +#endif + char buffer[1024] = {0}; + char* httpmethod = NULL; + char* filepath = NULL; + char* http_ver = NULL; + char* header_field_name = NULL; + char* header_field_val = NULL; + // + // Request Analysis + // +#ifdef DEBUG + printf("debug\r\n"); +#endif + switch(tcpcon.receive(buffer, 1023)) { + case 0: + printf("recieved buffer is empty.\r\n"); + msger.setStatusLine(400, "No Request"); + httpmethod = NULL; + filepath = NULL; + http_ver = NULL; + break; + case -1: + printf("failed to read data from client.\r\n"); + msger.setStatusLine(500, "Internal Server Error"); + httpmethod = NULL; + filepath = NULL; + http_ver = NULL; + break; + default: + printf("Recieved Data: %d\r\n\r\n%.*s\r\n",strlen(buffer),strlen(buffer),buffer); + // get HTTP method + httpmethod = strtok(buffer," "); + // get File path + filepath = strtok(NULL, " "); + // get HTTP version + http_ver = strtok(NULL, "\r\n"); +#ifdef DEBUG + printf("httpmethod: %s\r\n", httpmethod); + printf("file path: %s\r\n", filepath); + printf("http ver : %s\r\n", http_ver); +#endif + break; + } +#ifdef DEBUG + printf("debug before response\r\n"); +#endif + // + // Response + // + if (strcmp(httpmethod,"GET") == 0 ) { + printf("GET request incomming.\r\n"); + + // file calibration +#ifdef DEBUG + printf("file opening\r\n"); +#endif + fhandl.open(filepath,"rb"); + if(fhandl.arrival()) { + msger.setStatusLine(200, "OK"); + if(msger.setHeaderField("Content-Length", fhandl.getFileSize()))printf("buffer over flow"); + if(msger.setHeaderField("Connection", "keep-alive"))printf("buffer over flow"); + } else { + if(msger.setStatusLine(404, "NOT FOUND"))printf("buffer over flow"); + if(msger.setHeaderField("Connection", "close"))printf("buffer over flow"); +#ifdef DEBUG + printf("NOT FOUND\r\n"); +#endif + } + if(! ( strcmp(fhandl.getSuffix(), "htm" ) && + strcmp(fhandl.getSuffix(), "HTM" ) && + strcmp(fhandl.getSuffix(), "html") && + strcmp(fhandl.getSuffix(), "HTML") )) { + if(msger.setHeaderField("Content-Type", "text/html"))printf("buffer over flow"); + } else if (!strcmp(fhandl.getSuffix(), "ico" ) ) { + if(msger.setHeaderField("Content-Type", "image/png"))printf("buffer over flow"); + } else { + msger.setStatusLine(406, "not acceptable"); + } + + // Connection timeout field + if(msger.setHeaderField("Keep-Alive", "timeouit=15"))printf("buffer over flow"); +/* // Apply request header field to response header field + do { + //strtok(NULL, "\r\n"); + header_field_name = strtok(NULL, ":"); + header_field_name++; + //strtok(NULL, " "); + header_field_val = strtok(NULL, "\r\n"); + header_field_val++; +#ifdef DEBUG + printf("header_field_name adr: %d %s\r\n", header_field_name - 1, header_field_name); + printf("header_field_val adr: %d %s\r\n", header_field_val - 1, header_field_val); +#endif + if(header_field_name - 1 != NULL) { + //if(strcmp(header_field_name,"Connection") == 0) { + // if(msger.setHeaderField(header_field_name, "close"))printf("buffer over flow"); + //} else { + if(msger.setHeaderField(header_field_name, header_field_val))printf("buffer over flow"); + //} + } else { + break; + } + } while(1); +*/ +#ifdef DEBUG + //printf("status code : %d\r\n", status_code); + //printf("content type: %s\r\n", content_type); +#endif + + // send response + msger.sendHTTPResponse(tcpcon, fhandl); + + //file close +#ifdef DEBUG + if( +#endif + fhandl.close() +#ifndef DEBUG + ; +#endif +#ifdef DEBUG + == 0) + printf("file has closed\r\n"); + else if(EOF) + printf("failed to close the file\r\n"); +#endif + msger.resetHeader(); + printf("echo back done.\r\n"); + } + printf("Response to Request has done\r\n"); + } + printf("close connection.\r\ntcp server is listening...\r\n"); + tcpcon.close(); + tcpsvr.close(); + led2 = false; + } + led1 = false; + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTP_SERVER.h Tue Feb 16 10:59:31 2016 +0000 @@ -0,0 +1,51 @@ +//HTTP_SERVER.h +#ifndef HTTP_SERVER_H +#define HTTP_SERVER_H +#include "mbed.h" +#include "EthernetInterface.h" +#include "ResponseMessenger.h" +#include "FileHandler.h" +#include "string.h" +#include <stdlib.h> +using namespace std; + +enum PortNum { + TCP_PORT = 80 +}; + +class HttpServer +{ +public: + HttpServer(); + ~HttpServer(); + /** + * HTTP SERVER Initialization. + * This is called in the Constructor. + * You don't have to use but can call this if you have some reasons to init the server. + * @return result of init() as boolean. + * @retval TRUE SACCESS + * @retval FALSE + */ + bool init(); + /** + * Run the surver service while listening flag is true. + * @return state ending. + * @retval TRUE at error end. + * @retval FALSE at normal end. + */ + bool run(); + +private: + // Handlers + EthernetInterface eth; // Eternet + TCPSocketServer tcpsvr; // TCP server + TCPSocketConnection tcpcon; // TCP server connection clerk + ResponseMessenger msger; // Messenger for a client + FileHandler fhandl; // + // Param + bool keep_alive; + bool listening_flag; + char* req_buf[1024]; +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/handlers/FileHandler.h Tue Feb 16 10:59:31 2016 +0000 @@ -0,0 +1,32 @@ +/*FileHandler.h*/ +#ifndef FILE_HANDLER_H +#define FILE_HANDLER_H +#include "mbed.h" +#include "string.h" +#include <stdlib.h> + +using namespace std; +class FileHandler +{ +public: + FileHandler(); + ~FileHandler(); + FILE* open(const char*, const char*); + int close(); + virtual int getc(); + bool arrival(); + bool atEOF(); + bool hasError(); + char *getFullpath(); + char *getFilename(); + char *getSuffix(); + int getFileSize(); +private: + FILE *fp; + char *fullpath; + char *filename; + char *suffix; + char content_buffer[1024]; + int file_size; +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/handlers/Filehandler.cpp Tue Feb 16 10:59:31 2016 +0000 @@ -0,0 +1,136 @@ +#include "FileHandler.h" +#ifndef DEBUG +#define DEBUG +#endif +LocalFileSystem local("local"); + +FileHandler::FileHandler() +{ + fullpath = NULL; + filename = NULL; + suffix = NULL; + fp = NULL; + file_size = 0; +} +FileHandler::~FileHandler() +{ + if (fullpath != NULL) free(fullpath); + if (fp != NULL) fclose(fp); +} + +FILE* FileHandler::open +( const char* arg_filepath, + const char* arg_mode +) +{ + FILE *tmp; + + printf("\r\nfp: %d@FileHandler::open\r\n", fp); + if (fullpath != NULL) free(fullpath); + fullpath = (char*)malloc(sizeof(char) * (strlen("/local/") + strlen(arg_filepath) + strlen("index.htm") + 1)); + printf("\r\nfp: %d@FileHandler::open\r\n", fp); + + // Path formatting + if (arg_filepath[0] == '/') { + sprintf(fullpath, "/local/%s", arg_filepath + 1); + } else { + sprintf(fullpath, "/local/%s", arg_filepath); + } + // if the argument has no file name but directory, defalt settiing. + if (fullpath[strlen(fullpath) - 1] == '/') + strcat(fullpath, "index.htm"); + // store the file name part to a pointer + filename = strrchr(fullpath, '/'); + if(filename != NULL) filename++; // remove '/' and just get only the file name. + // store the suffix part to a pointer + suffix = strchr(filename, '.'); + if(suffix != NULL) suffix++; // remove '.' and just get only the suffix. +#ifdef DEBUG + printf("full path: %s\r\nfilename: %s\r\nsuffix: %s\r\n", getFullpath(), getFilename(), getSuffix()); +#endif + fp = fopen(fullpath, arg_mode); +#ifdef DEBUG + printf("file opened@FileHandler::open\r\n"); +#endif + // mesure file size + file_size = 0; + tmp = fp; + if(tmp != NULL ) { + printf("\r\nfile content\r\n"); + int ctmp; + while(1) { + ctmp = fgetc(tmp); + if(ctmp != EOF) { + printf("%c", ctmp); + file_size++; + } else { + printf("[EOF]\r\n"); + break; + } + } + printf("file size: %d\r\n", file_size); + if(fseek(tmp, 0L, SEEK_SET) != 0) { + printf("fseek failed\r\n"); + } + } else { + file_size = 0; + } + + return fp; +} +int FileHandler::close() +{ + int tmp; + + if(fp != NULL){ + tmp = fclose(fp); + fp = NULL; + return tmp; + } else{ + return 1; + } +} + +int FileHandler::getc() +{ + int tmp = fgetc(fp); + + if(0x20 < tmp && tmp < 0x7e) + printf("%c", tmp); + else if (tmp == '\r') + printf("\r"); + else if (tmp == '\n') + printf("\n"); + else + printf("@"); + + return tmp;//fgetc(fp); +} +bool FileHandler::arrival() +{ + return (bool)fp; +} +bool FileHandler::atEOF() +{ + return (bool)feof(fp); +} +bool FileHandler::hasError() +{ + return (bool)ferror(fp); +} +char *FileHandler::getFullpath() +{ + return fullpath; +} +char *FileHandler::getFilename() +{ + return filename; +} +char *FileHandler::getSuffix() +{ + return suffix; +} +int FileHandler::getFileSize() +{ + return file_size; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/handlers/ResponseMessenger.cpp Tue Feb 16 10:59:31 2016 +0000 @@ -0,0 +1,180 @@ +#include "ResponseMessenger.h" + +const char ResponseMessenger::http_ver[9] = "HTTP/1.1"; +ResponseMessenger::ResponseMessenger() +{ + // Status-Line + status_code = 0; + reason_phrase[0] = '\0'; + header_field_buffer[0]='\0'; + // Response Header +} +ResponseMessenger::~ResponseMessenger() +{ +} +int ResponseMessenger::resetHeader() +{ + // Status-Line + status_code = 0; + reason_phrase[0] = '\0'; + header_field_buffer[0]='\0'; + // Response Header + return 0; +} +int ResponseMessenger::setStatusLine( + int arg_status_code, + const char* arg_reason_phrase +) +{ + status_code = arg_status_code; + strcpy(reason_phrase, arg_reason_phrase); + + // To be safe on the sage side + reason_phrase[REASON_PHRASE_SIZE - 1] = '\0'; + // Send 0 if arg str size is too big, else -1. + if (strlen(arg_reason_phrase) < REASON_PHRASE_SIZE) + return 0; + else + return -1; +} + +int ResponseMessenger::setHeaderField( + const char* arg_field_name, const char* arg_field_val) +{ + const int nField = 4; + char registered_field_name[nField][32]= { + "Connection", + "Location", + "Keep-Alive", + "Content-Type" + }; + bool flag = false; + char header_field_line_buffer[128]; + int buffer_size = strlen(header_field_buffer); + + for (int i = 0; i < nField; i++) { + if(strcmp(arg_field_name, registered_field_name[i]) == 0) + flag = true; + } + if(flag) { + sprintf(header_field_line_buffer, "%s: %s\r\n", arg_field_name, arg_field_val); + strcat(header_field_buffer, header_field_line_buffer); + printf("header field: \r\n%s\r\n", header_field_buffer); + } + // To be safe on the sage side + header_field_buffer[HEADER_FIELDS_SIZE - 1] = '\0'; + // Send 0 if arg str size is too big, else -1. + if (buffer_size + strlen(arg_field_name) + strlen(arg_field_val) < HEADER_FIELDS_SIZE + 1) + return 0; + else + return -1; +} + +int ResponseMessenger::setHeaderField( + const char* arg_field_name, int arg_field_val) +{ + const int nField = 1; + char registered_field_name[nField][32]= { + "Content-Length" + }; + bool flag = false; + char header_field_line_buffer[128]; + int buffer_size = strlen(header_field_buffer); + + for (int i = 0; i < nField; i++) { + if(strcmp(arg_field_name, registered_field_name[i]) == 0) + flag = true; + } + if(flag) { + sprintf(header_field_line_buffer, "%s: %d\r\n", arg_field_name, arg_field_val); + strcat(header_field_buffer, header_field_line_buffer); + printf("header field: \r\n%s\r\n", header_field_buffer); + } + // To be safe on the sage side + header_field_buffer[HEADER_FIELDS_SIZE - 1] = '\0'; + // Send 0 if arg str size is too big, else -1. + if (buffer_size + strlen(arg_field_name) + 10 < HEADER_FIELDS_SIZE + 1) + return 0; + else + return -1; +} +int ResponseMessenger::getStatusCode() +{ + return status_code; +} + +char ResponseMessenger::sendHTTPResponse( + TCPSocketConnection &arg_connection) +{ + int err_log = 0; + int err_code = 0; + enum { + MAX_BUFFER_SIZE = 1024 + }; + char buffer[MAX_BUFFER_SIZE] = "\0"; + + // + // Header + // + printf("[send]Header\r\n"); + // Status Line + sprintf(buffer, "%s %d %s\r\n", http_ver, status_code, reason_phrase); + buffer[MAX_BUFFER_SIZE - 1] = '\0'; + err_log = arg_connection.send_all(buffer, strlen(buffer)); + if(err_log < 0) err_code = ((err_code << 1) | 1); + // Response Header + err_log = arg_connection.send_all(header_field_buffer, strlen(header_field_buffer)); + if(err_log < 0) err_code = ((err_code << 1) | 1); + // Blank line + err_log = arg_connection.send_all("\r\n", strlen("\r\n")); + if(err_log < 0) err_code = ((err_code << 1) | 1); + printf("[Header has sent]\r\n"); + //return error code + return err_code << 2; + +} + +char ResponseMessenger::sendHTTPResponse( + TCPSocketConnection &arg_connection, + FileHandler &arg_file) +{ + int err_log = 0; + int err_code = 0; + enum { + MAX_BUFFER_SIZE = 1024 + }; + signed char buffer[MAX_BUFFER_SIZE]; + + // + // Header + // + err_code = sendHTTPResponse(arg_connection); + // + // Body + // + if (arg_file.arrival() && status_code == 200) { + printf("[send]Body\r\n"); + do { + int i = 0; + do { + buffer[i++] = arg_file.getc();//return a byte from file ponter, or -1 if EOF or ERROR + } while ((i < MAX_BUFFER_SIZE - 1) && (buffer[i - 1] != EOF)); + if(buffer[i - 1] == EOF)buffer[i - 1] = '\0'; + buffer[i] = '\0'; + if (!arg_file.hasError()) { + err_log = arg_connection.send_all((char*)buffer, i); + //printf("buffer log: %s", buffer); + } + if (arg_file.hasError()) printf("\r\n[ERR][ERR][ERR]\r\n"); + if (arg_file.atEOF()) printf("\r\n[EOF][EOF][EOF]\r\n"); + } while (!arg_file.atEOF() && !arg_file.hasError()); + printf("[Body has sent]\r\n"); + + if (err_log < 0) err_code = ((err_code) | 2); + if (!arg_file.hasError())err_code = ((err_code) | 1); + } + else{ + printf("[No Body]\r\n"); + } + return (char)err_code; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/handlers/ResponseMessenger.h Tue Feb 16 10:59:31 2016 +0000 @@ -0,0 +1,50 @@ +/* ResponseMessenger.h */ +#ifndef RESPONSE_MESSENGER_H +#define RESPONSE_MESSENGER_H +#include "mbed.h" +#include "string.h" +#include "EthernetInterface.h" +#include "FileHandler.h" +#include <stdlib.h> +using namespace std; + +class ResponseMessenger +{ + enum { + REASON_PHRASE_SIZE = 32, + HEADER_FIELDS_SIZE = 2048 + }; +public: + ResponseMessenger(); + ~ResponseMessenger(); + int resetHeader(); + int setStatusLine(int,const char*); + int setHeaderField(const char*, const char*); + int setHeaderField(const char*, int); + int getStatusCode(); + /** + * Function to send response messages. + * just header only + * @return char + * @retval error code + */ + char sendHTTPResponse(TCPSocketConnection&); + /** + * Function to send response messages. + * @return char + * @retval error code + */ + char sendHTTPResponse(TCPSocketConnection&, FileHandler&); +private: + // Status-Line + static const char http_ver[9]; + int status_code; + char reason_phrase[REASON_PHRASE_SIZE]; + // Header Field buffer + // - General Header + // - Response Header + // - Entity Header + char header_field_buffer[HEADER_FIELDS_SIZE]; +}; + +#endif \ No newline at end of file