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 Akifumi Takahashi

Files at this revision

API Documentation at this revision

Comitter:
aktk
Date:
Tue Feb 16 10:59:31 2016 +0000
Child:
1:3a1fe94c6e42
Commit message:
add comment

Changed in this revision

HTTP_SERVER.cpp Show annotated file Show diff for this revision Revisions of this file
HTTP_SERVER.h Show annotated file Show diff for this revision Revisions of this file
handlers/FileHandler.h Show annotated file Show diff for this revision Revisions of this file
handlers/Filehandler.cpp Show annotated file Show diff for this revision Revisions of this file
handlers/ResponseMessenger.cpp Show annotated file Show diff for this revision Revisions of this file
handlers/ResponseMessenger.h Show annotated file Show diff for this revision Revisions of this file
--- /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