The library with which to configure a Web Socket Server on a Mbed. This lib was coded by a day at least one year before when this description is written. It will be updated adopting mbed os 5.

Dependencies:   mbedTLSLibrary

Dependents:   SIMPLE_WSS

Files at this revision

API Documentation at this revision

Comitter:
aktk
Date:
Sat Mar 03 19:01:29 2018 +0000
Parent:
1:73f2f67d1732
Commit message:
Put out the HTTP_SERVER lib and copy&pasted just the handler directory from the lib to this.

Changed in this revision

HTTP_SERVER.lib 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
diff -r 73f2f67d1732 -r ccaae77f91b8 HTTP_SERVER.lib
--- a/HTTP_SERVER.lib	Sat Mar 03 18:47:34 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-https://developer.mbed.org/users/aktk/code/HTTP_SERVER/#0ee7d100db24
diff -r 73f2f67d1732 -r ccaae77f91b8 handlers/FileHandler.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/handlers/FileHandler.h	Sat Mar 03 19:01:29 2018 +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
diff -r 73f2f67d1732 -r ccaae77f91b8 handlers/Filehandler.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/handlers/Filehandler.cpp	Sat Mar 03 19:01:29 2018 +0000
@@ -0,0 +1,137 @@
+#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\n"
+    //       "fp: %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("fp: %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);
+#ifdef DEBUG
+    if(0x20 < tmp && tmp < 0x7e)
+        printf("%c", tmp);
+    else if (tmp == '\r')
+        printf("\r");
+    else if (tmp == '\n')
+        printf("\n");
+    else
+        printf("@");
+#endif
+    return tmp;
+}
+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
diff -r 73f2f67d1732 -r ccaae77f91b8 handlers/ResponseMessenger.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/handlers/ResponseMessenger.cpp	Sat Mar 03 19:01:29 2018 +0000
@@ -0,0 +1,204 @@
+#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';
+    //  Response Header
+    header_field_buffer[0]='\0';
+    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 = 7;
+    char registered_field_name[nField][32]= {
+        "Connection",
+        "Location",
+        "Keep-Alive",
+        "Content-Type",
+        "Upgrade",
+        "Sec-WebSocket-Accept",
+        "Access-Control-Allow-Origin"
+    };
+    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("(RM) 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("(RM) 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::rmHeaderField(
+    const char* arg_field_name)
+{
+    char* removedLineHead;
+    char* removedLineEnd;
+    int  buffer_size;
+    
+    //  Look for the head of the line to want to remove
+    removedLineHead = strstr(header_field_buffer, arg_field_name);
+    if(removedLineHead == NULL) return -1;
+    //  Look for the first "\r\n" which is the end of the line
+    removedLineEnd = strstr(removedLineHead, "\r\n");
+    removedLineEnd += 3; //pointing next line head or '\0' if the line of the last one.
+    buffer_size = strlen(removedLineEnd);
+    
+    for(int i = 0; i < buffer_size + 1; i++)
+        removedLineHead[i] = removedLineEnd[i];
+    
+    return 0;
+}
+
+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("(RM) [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("(RM) [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("(RM) [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("(RM) buffer log: %s",  buffer);
+            }
+            if (arg_file.hasError()) printf("(RM)---[ERR]---\r\n");
+            if (arg_file.atEOF())    printf("(RM)---[EOF]---\r\n");
+        } while (!arg_file.atEOF() && !arg_file.hasError());
+        printf("(RM) [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("(RM) [No Body]\r\n");
+    }
+    return (char)err_code;
+}
\ No newline at end of file
diff -r 73f2f67d1732 -r ccaae77f91b8 handlers/ResponseMessenger.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/handlers/ResponseMessenger.h	Sat Mar 03 19:01:29 2018 +0000
@@ -0,0 +1,51 @@
+/*  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 rmHeaderField(const char*);
+    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