The lib with which to make LPC1768 a simple HTTP server. This have not yet implemented. fopen() DOESN'T WORK after EthernetInterface::connect() is called as using mbed-os 5.4~. See also https://os.mbed.com/questions/80658/HardFault-occurs-when-fopen-is-called-af/ or https://github.com/ARMmbed/mbed-os/issues/6578 and https://github.com/ARMmbed/mbed-os/issues/6624

Fork of HTTP_SERVER by Akifumi Takahashi

HTTP_SERVER.cpp

Committer:
aktk
Date:
2018-03-23
Revision:
18:ad5c461905bd
Parent:
17:ce5845164001

File content as of revision 18:ad5c461905bd:

#include "HTTP_SERVER.h"
#include "string"
//#ifndef HTTP_SERVER_DEBUG
#define HTTP_SERVER_DEBUG
//#endif
/*
LOG:
"sys_thread_new number error" is occurred when an instance of this class is instantiated in main() in main.cpp
This case wasn't occured with the APIs of mbed os 2.
So, inserting some DEBUG_PRINT_LINE, and finding where is wrong.

The error seems to be occurred in init() in the above case.

TCP_PORT=80 redefine
tcp_port->port

The error seems to be occurred while ethernet->connect() is proceesing.

The error seems to be caused by something wrong with stack.
When modify (char* -> char) req_buf[1024] in the .h file,
the error message became: "CMSIS-RTOS error: Stack underflow (status: 0x1, task ID: 0x10002678, task name: )"
UNDERFLOW means that there is a value which is too fine(or high definition) to express.
(Why was the type char*?)

(char)req_buf[1024] was not uesed anywhere...
so it was deleted.

(bool)keep-alive was also not uesed so deleted it.

After doing those above, the error massage was DERAYED but
it even now occur.
and when some array stack(such like char buffer[1024] -> [256])'s size was decreased,
the message was more derayed.
Therefore it can be thought that the error is causeed by stack overflow.
*/

namespace HTTP_SERVER
{
void DEBUG_PRINT_NAME()
{
#ifdef HTTP_SERVER_DEBUG
    printf("(DEBUG LINE: HTTP_SERVER) ");
#endif
}

void DEBUG_PRINT_LINE(const char* arg_line)
{
#ifdef HTTP_SERVER_DEBUG
    DEBUG_PRINT_NAME();
    printf(arg_line);
    printf("\r\n");
#endif
}
template<typename T>
void DEBUG_PRINT_LINE(const char* arg_line, T arg_t)
{
#ifdef HTTP_SERVER_DEBUG
    DEBUG_PRINT_NAME();
    printf(arg_line, arg_t);
    printf("\r\n");
#endif
}
template<typename T1, typename T2>
void DEBUG_PRINT_LINE(const char* arg_line, T1 arg_t1, T2 arg_t2)
{
#ifdef HTTP_SERVER_DEBUG
    DEBUG_PRINT_NAME();
    printf(arg_line, arg_t1, arg_t2);
    printf("\r\n");
#endif
}
}
using namespace HTTP_SERVER;

HttpServer::HttpServer()
{
    DEBUG_PRINT_LINE("=DEBUG MODE=");
    net = new EthernetInterface();
    port = TCP_PORT;
    backlog  = 1;
    //keep_alive = (false);
    listening_flag = (false);
    socket_connection = false;
    DEBUG_PRINT_LINE("A HTTP_SERVER has been inistantiated.");
}

HttpServer::~HttpServer()
{
}

bool HttpServer::init()
{
    DEBUG_PRINT_LINE("The HTTP SERVER is being initiated");
    //  Ethernet Initialization
    //  Ethernet Connecting setup
    if(net->connect()) {
        printf("(HTTP_SERVER) Error!@EthernetInterface::connect()\r\n");
        return false;
    } else {
        printf("(HTTP_SERVER) IP Address is %s\r\n", net->get_ip_address());
    }

    ftest.func();
    //  TCP Socket setup
    //  To open Server-side PORT
    if(server.open(net) < 0) {
        printf("(HTTP_SERVER) Error!@TCPSocketServer::open()\r\n");
        return false;
    } else {
        printf("(HTTP_SERVER) TCP Server has successfully opened\r\n");
    }
    if(server.bind(port)< 0) {
        printf("(HTTP_SERVER) Error!@TCPSocketServer::bind()\r\n");
        return false;
    } else {
        printf("(HTTP_SERVER) TCP Server has bounden!\r\n");
    }
    //  Server start listening Request from a web browser.
    if(server.listen(backlog) < 0) {
        printf("(HTTP_SERVER) tcp server listen failed.\r\n");
        return false;
    } else {
        listening_flag = true;
        printf("(HTTP_SERVER) tcp server is listening...\r\n");
    }

    return true;
}

bool HttpServer::run()
{

    DigitalOut led1(LED1);
    DigitalOut led2(LED1);


    DEBUG_PRINT_LINE("The HTTP SERVER is starting running");
    while (listening_flag) {
        led1 = true;
        //  blocking mode (never timeout)
        //  waiting client connection
        printf("(HTTP_SERVER) waiting connection\r\n");
        if(server.accept(&client_socket, &client_address) < 0) {
            printf("(HTTP_SERVER) failed to accept connection.\r\n");
            return -1;
        } else {
            printf("(HTTP_SERVER) connection success!\r\nIP: %s\r\n",client_address.get_ip_address());
            socket_connection = true;
            led2 = true;
        }
        //  When conected
        while (socket_connection) {
            printf("(HTTP_SERVER) connected\r\n");

            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
            //
            printf("(HTTP_SERVER) Request Analysis\r\n");
            analyzeRequest(buffer, 1023, httpmethod, filepath, http_ver);
            DEBUG_PRINT_LINE("httpmethod: %s", httpmethod);
            DEBUG_PRINT_LINE("file path:  %s", filepath);
            DEBUG_PRINT_LINE("http ver :  %s", http_ver);
            //
            //  Response
            //
            sendResponse(httpmethod, filepath, http_ver);
            //
            //
            //
        }
        printf("(HTTP_SERVER) close connection.\r\ntcp server is listening...\r\n");
        client_socket.close();
        led2 = false;
    }
    server.close();
    listening_flag = false;
    led1 = false;
    return 0;

}

bool HttpServer::analyzeRequest(char* buffer, int buffer_size, char* &httpmethod, char* &filepath, char* &http_ver)
{

    DEBUG_PRINT_LINE("Request Analysis");
    switch(client_socket.recv(buffer, buffer_size)) {
        case 0:
            DEBUG_PRINT_LINE("recieved buffer is empty.");
            msger.setStatusLine(400, "No Request");
            if(msger.setHeaderField("Connection", "Close"))DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
            httpmethod    = NULL;
            filepath      = NULL;
            http_ver      = NULL;
            socket_connection = false;
            break;
        case -1:
            DEBUG_PRINT_LINE("failed to read data from client.");
            msger.setStatusLine(500, "Internal Server Error");
            if(msger.setHeaderField("Connection", "Close"))DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
            httpmethod    = NULL;
            filepath      = NULL;
            http_ver      = NULL;
            socket_connection = false;
            break;
        default:
            DEBUG_PRINT_LINE("Recieved Data: %d",strlen(buffer));
            DEBUG_PRINT_LINE("-->\r\n");
            DEBUG_PRINT_LINE("%.*s[End of Request]",strlen(buffer),buffer);
            //  get HTTP method, File path, HTTP version
            httpmethod = strtok(buffer," ");
            filepath = strtok(NULL, " ");
            http_ver = strtok(NULL, "\r\n");
            break;
    }
    return true;
}

bool HttpServer::sendResponse(char* httpmethod, char* filepath, char* http_ver)
{
    if (strcmp(httpmethod,"GET") == 0 ) {
        DEBUG_PRINT_LINE("GET request incomming.");

        //  file calibration
        DEBUG_PRINT_LINE("file opening");
        DEBUG_PRINT_LINE("filepath: %s", filepath);
        fhndl.open(filepath,"rb");
        if(fhndl.arrival()) {
            msger.setStatusLine(200, "OK");
            if(msger.setHeaderField("Content-Length", fhndl.getFileSize()))     DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
            if(msger.setHeaderField("Connection", "keep-alive"))                DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
        } else {
            if(msger.setStatusLine(404, "NOT FOUND"))                           DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
            if(msger.setHeaderField("Connection", "Close"))                     DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
            DEBUG_PRINT_LINE("NOT FOUND");
        }
        if(         !strcmp(fhndl.getSuffix(), "htm" ) ||
                    !strcmp(fhndl.getSuffix(), "HTM" ) ||
                    !strcmp(fhndl.getSuffix(), "html") ||
                    !strcmp(fhndl.getSuffix(), "HTML")) {
            if(msger.setHeaderField("Content-Type", "text/html"))               DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
        } else if(  !strcmp(fhndl.getSuffix(), "js"  )) {
            if(msger.setHeaderField("Content-Type", "text/javascript"))         DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
        } else if ( !strcmp(fhndl.getSuffix(), "ico" )) {
            if(msger.setHeaderField("Content-Type", "image/png"))               DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
        } else if ( !strcmp(fhndl.getSuffix(), "png" ) ||
                    !strcmp(fhndl.getSuffix(), "PNG" )) {
            if(msger.setHeaderField("Content-Type", "image/png"))               DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
        } else if ( !strcmp(fhndl.getSuffix(), "jpg" ) ||
                    !strcmp(fhndl.getSuffix(), "JPG" )) {
            if(msger.setHeaderField("Content-Type", "image/jpg"))               DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");
        } else {
            msger.setStatusLine(406, "not acceptable");
        }

        //  Connection timeout field
        if(msger.setHeaderField("Keep-Alive", "timeouit=15"))                   DEBUG_PRINT_LINE("buffer over flow @ ResponseMessenger");

        //  send response
        msger.sendHTTPResponse(client_socket, fhndl);

        //file close
        if( fhndl.close()== 0)
            DEBUG_PRINT_LINE("file has closed");
        else if(EOF)
            DEBUG_PRINT_LINE("failed to close the file");

        msger.resetHeader();
        DEBUG_PRINT_LINE("echo back done.");
    }
    if (httpmethod == NULL) {
        msger.sendHTTPResponse(client_socket);
        msger.resetHeader();
        DEBUG_PRINT_LINE("echo back done.");
        socket_connection = false;
    }
    printf("(HTTP_SERVER) Response to Request has done\r\n");
    
    return true;
}