A simple web server mainly based on ideas from Jasper Schuurmans Netduino web server

Dependents:   RdBlindsServer SpideyWallWeb RdGasUseMonitor

A fast and reliable web server for MBED! http://robdobson.com/2015/08/a-reliable-mbed-webserver/

It has a very neat way to implement REST commands and can serve files from local storage (on LPC1768 for instance) and from SD cards. It also has a caching facility which is particularly useful for serving files from local storage.

The server can be run in the main() thread (and has a sub-2ms response time if this is done) or in a mbed-rtos thread which increases the response time to (a still respectable) 30ms or so.

The latest project that uses this is here - https://developer.mbed.org/users/Bobty/code/SpideyWallWeb/

int main (void)
{
    // Ethernet interface
    EthernetInterface::init();

    // Connect ethernet
    EthernetInterface::connect();

    // Init the web server
    pc.printf("Starting web server\r\n");
    char* baseWebFolder = "/sd/";  // should be /sd/ for SDcard files - not used for local file system
    RdWebServer webServer;
    
    // Add commands to handle the home page and favicon
    webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, "index.htm", true);
    webServer.addCommand("favicon.ico", RdWebServerCmdDef::CMD_LOCALFILE, NULL, NULL, true);
    
    // Add the lightwall control commands
    webServer.addCommand("name", RdWebServerCmdDef::CMD_CALLBACK, &lightwallGetSystemName);
    webServer.addCommand("clear", RdWebServerCmdDef::CMD_CALLBACK, &lightwallClear);
    webServer.addCommand("rawfill", RdWebServerCmdDef::CMD_CALLBACK, &lightwallRawFill);
    webServer.addCommand("fill", RdWebServerCmdDef::CMD_CALLBACK, &lightwallFill);
    webServer.addCommand("showleds", RdWebServerCmdDef::CMD_CALLBACK, &lightwallShowLeds);
    
    // Start the server
    webServer.init(WEBPORT, &led4, baseWebFolder);
    webServer.run();

}

// Get system name - No arguments required
char* lightwallGetSystemName(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
                int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
{
    // Perform any required actions here ....

    // ...

    // Return the system name
    return systemName;
}

This server was originally based on a Netduino web server from Jasper Schuurmans but has been optimised for speed.

Files at this revision

API Documentation at this revision

Comitter:
Bobty
Date:
Fri Feb 06 14:17:47 2015 +0000
Parent:
5:e6286b529d6b
Child:
7:fe7c33f7fbb8
Commit message:
Working with threaded server and SD card stack extended to stop crashes

Changed in this revision

RdWebServer.cpp Show annotated file Show diff for this revision Revisions of this file
RdWebServer.h Show annotated file Show diff for this revision Revisions of this file
--- a/RdWebServer.cpp	Tue Feb 03 12:08:12 2015 +0000
+++ b/RdWebServer.cpp	Fri Feb 06 14:17:47 2015 +0000
@@ -9,57 +9,6 @@
 #define MAX_CMDSTR_LEN 100
 #define MAX_ARGSTR_LEN 100
 
-bool RdFileCacheEntry::readLocalFileIntoCache(char* fileName)
-{
-    printf("Reading into cache %s\n\r", fileName);
-    LocalFileSystem local("local");
-    FILE* fp = fopen(fileName, "r");
-    if (fp == NULL)
-    {
-        printf("Failed to open file\n\r");
-        return false;
-    }
-    printf("Seeking\n\r");
-    fseek(fp, 0, SEEK_END);
-    _nFileLen = (int)ftell(fp);
-    _pFileContent = new char[_nFileLen];
-    printf("Len %d Buf %08x\n\r", _nFileLen, _pFileContent);
-    if (!_pFileContent)
-    {
-        printf("Failed to allocate %lu\n\r", _nFileLen);
-        fclose(fp);
-        return false;
-    }
-    printf("Allocated\n\r");
-    memset(_pFileContent, 0, _nFileLen);
-    fseek(fp, 0, SEEK_SET);
-    char* pMem = _pFileContent;
-    char fileBuf[100];
-    int totCnt = 0;
-    int rdCnt = 0;
-    printf("Reading\n\r");
-    while (true)
-    {
-        int toRead = _nFileLen - totCnt;
-        if (toRead > sizeof(fileBuf))
-            toRead = sizeof(fileBuf);
-        if (toRead <= 0)
-            break;
-        rdCnt = fread(fileBuf, sizeof(char), toRead, fp);
-        if (rdCnt <= 0)
-            break;
-        printf("Read %d tot %d of %d\n\r", rdCnt, totCnt, _nFileLen);
-        memcpy(pMem, fileBuf, rdCnt);
-        pMem += rdCnt;
-        totCnt += rdCnt;
-    }
-    printf("Done read\n\r");
-    fclose(fp);
-    printf("Success in caching %d bytes (read %d)\n\r", _nFileLen, totCnt);
-    _bCacheValid = true;
-    return true;
-}
-
 RdWebServer::RdWebServer()
 {
     _serverIsListening = false;
@@ -79,31 +28,468 @@
     _pStatusLed = pStatusLed;
     _pBaseWebFolder = pBaseWebFolder;
         
-//    _socketSrv.set_blocking(true);
-
+    _socketSrv.set_blocking(true);
 
     //setup tcp socket
     if(_socketSrv.bind(port)< 0) 
     {
-        printf("TCP server bind fail\n\r");
+        pc.printf("TCP server bind fail\n\r");
         return false;
     }
     else 
     {
-//        printf("TCP server bind success\n\r");
+//        pc.printf("TCP server bind success\n\r");
         _serverIsListening = true;
     }
 
     if(_socketSrv.listen(1) < 0)
     {
-        printf("TCP server listen fail\n\r");
+        pc.printf("TCP server listen fail\n\r");
         return false;
     }
     else 
     {
-        printf("TCP server is listening...\r\n");
+        pc.printf("TCP server is listening...\r\n");
+    }
+    
+    return true;
+}
+
+void RdWebServer::handleReceivedHttp(TCPSocketConnection &client)
+{
+    pc.printf("Received Data: %d\n\r\n\r%.*s\n\r",strlen(_buffer),strlen(_buffer),_buffer);
+    if (strncmp(_buffer, "GET ", 4) == 0)
+    {
+        pc.printf("GET request\n\r");
+        char cmdStr[MAX_CMDSTR_LEN];
+        char argStr[MAX_ARGSTR_LEN];
+        if (extractCmdArgs(_buffer+3, cmdStr, MAX_CMDSTR_LEN, argStr, MAX_ARGSTR_LEN))
+        {
+            pc.printf("CmdStr %s\n\r", cmdStr);
+            pc.printf("ArgStr %s\n\r", argStr);
+            bool cmdFound = false;
+            for (std::vector<RdWebServerCmdDef*>::iterator it = _commands.begin() ; it != _commands.end(); ++it)
+            {
+    //                            pc.printf("Testing <<%s>> with <<%s>>\r\n", (*it)->_pCmdStr, cmdStr);
+                if (strcasecmp((*it)->_pCmdStr, cmdStr) == 0)
+                {                                    
+                    pc.printf("FoundCmd <%s> Type %d\n\r", cmdStr, (*it)->_cmdType);
+                    cmdFound = true;
+                    if ((*it)->_cmdType == RdWebServerCmdDef::CMD_CALLBACK)
+                    {
+                        char* respStr = ((*it)->_callback)(cmdStr, argStr);
+                        client.send(respStr, strlen(respStr));
+                    }
+                    else if ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE)
+                    {
+                        if ((*it)->_substFileName[0] != '\0')
+                            handleLocalFileRequest((*it)->_substFileName, argStr, client, _httpHeader, (*it)->_bCacheIfPossible);
+                        else
+                            handleLocalFileRequest(cmdStr, argStr, client, _httpHeader, (*it)->_bCacheIfPossible);
+                    }
+                    else if ((*it)->_cmdType == RdWebServerCmdDef::CMD_SDORUSBFILE)
+                    {
+                        if ((*it)->_substFileName[0] != '\0')
+                            handleSDFileRequest((*it)->_substFileName, argStr, client, _httpHeader);
+                        else
+                            handleSDFileRequest(cmdStr, argStr, client, _httpHeader);
+                    }
+                    break;
+                }
+            }
+            // If command not found see if it is a local file
+            if (!cmdFound)
+                handleSDFileRequest(cmdStr, argStr, client, _httpHeader);
+        }
+    }
+}
+
+void RdWebServer::run()
+{
+
+    while (1)
+    {
+        TCPSocketConnection client;
+        pc.printf("Waiting for TCP connection\r\n");
+        if(_socketSrv.accept(client)<0) 
+        {
+            pc.printf("TCP Socket failed to accept connection\n\r");
+        }
+        else
+        {
+            pc.printf("Connection from IP: %s\n\r",client.get_address());
+            if (_pStatusLed != NULL)
+                *_pStatusLed = true;
+                
+            // Get received data
+            int rxLen = client.receive(_buffer, HTTPD_MAX_REQ_LENGTH);
+            if (rxLen == -1)
+            {
+                continue;
+            }
+            else if (rxLen == 0)
+            {
+                pc.printf("received buffer is empty.\n\r");
+                continue;                
+            }
+            else if (rxLen > HTTPD_MAX_REQ_LENGTH)
+            {
+                sprintf(_httpHeader,"HTTP/1.1 413 Request Entity Too Large \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
+                client.send(_httpHeader,strlen(_httpHeader));
+                client.send(_buffer, rxLen);
+                continue;
+            }
+            _buffer[rxLen] = '\0';
+
+            // Handle buffer
+            handleReceivedHttp(client);
+//            const char * msg = "Hello World\n\r\n\r";
+//            sprintf(_buffer,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text/html\n\rConnection: Close\n\r\n\r", strlen(msg));
+//            client.send(_buffer,strlen(_buffer));
+//            client.send( const_cast<char*>(msg), strlen(msg));
+        }
     }
     
+//    while (1) 
+//    {
+//        TCPSocketConnection Clnt;
+//        printf("Accept\n");
+//        int ret = _socketSrv.accept(Clnt);
+//        if ( ret < 0) {
+//            printf("no connection\n");            
+//        } else {
+//            printf("Client (IP=%s) is connected\n", Clnt.get_address());
+//            char buff[512];            
+//            int result = Clnt.receive(buff, 511);
+//            if(result < 0 )
+//                printf("The horror\n ");
+//            else {
+//               if(result >= 511)
+//                 buff[511] = 0;
+//               else
+//                 buff[result + 1] = 0;
+//                 
+//               printf("%s\n",buff);
+//            }
+//            const char * msg = "Hello World\n\r\n\r";
+//            sprintf(buff,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text/html\n\rConnection: Close\n\r\n\r", strlen(msg));
+//            Clnt.send(buff,strlen(buff));
+//            Clnt.send( const_cast<char*>(msg), strlen(msg));
+//        }        
+//    }
+//
+//    //listening for http GET request
+//    while (isListening())
+//    {
+//        //blocking mode(never timeout)
+//        if(_socketSrv.accept(client)<0) 
+//        {
+//            pc.printf("TCP Socket failed to accept connection\n\r");
+//        }
+//        else
+//        {
+//            client.set_blocking(false, 1000);
+//            pc.printf("Connection from IP: %s\n\r",client.get_address());
+//            if (_pStatusLed != NULL)
+//                *_pStatusLed = true;
+//            Timer connectLimitTimer;
+//            connectLimitTimer.start();
+//            
+//            while(connectLimitTimer.read() < 5)  // 5 seconds timeout on HTTP operation
+//            {
+//                int rxLen = client.receive(buffer, 1023);
+//                if (rxLen == -1)
+//                {
+//                    continue;
+//                }
+//                else if (rxLen == 0)
+//                {
+//                    pc.printf("received buffer is empty.\n\r");
+//                    break;                
+//                }
+//                else if (rxLen >= 1024)
+//                {
+//                    sprintf(httpHeader,"HTTP/1.1 413 Request Entity Too Large \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
+//                    client.send(httpHeader,strlen(httpHeader));
+//                    client.send(buffer, rxLen);
+//                    break;
+//                }
+//                buffer[rxLen] = '\0';
+////                pc.printf("Received Data: %d\n\r\n\r%.*s\n\r",strlen(buffer),strlen(buffer),buffer);
+//                if (strncmp(buffer, "GET ", 4) == 0)
+//                {
+////                    pc.printf("GET request\n\r");
+//                    char cmdStr[MAX_CMDSTR_LEN];
+//                    char argStr[MAX_ARGSTR_LEN];
+//                    if (extractCmdArgs(buffer+3, cmdStr, MAX_CMDSTR_LEN, argStr, MAX_ARGSTR_LEN))
+//                    {
+//                        pc.printf("CmdStr %s\n\r", cmdStr);
+//                        pc.printf("ArgStr %s\n\r", argStr);
+//                        bool cmdFound = false;
+//                        for (std::vector<RdWebServerCmdDef*>::iterator it = _commands.begin() ; it != _commands.end(); ++it)
+//                        {
+////                            pc.printf("Testing <<%s>> with <<%s>>\r\n", (*it)->_pCmdStr, cmdStr);
+//                            if (strcasecmp((*it)->_pCmdStr, cmdStr) == 0)
+//                            {                                    
+//                                pc.printf("FoundCmd <%s> Type %d\n\r", cmdStr, (*it)->_cmdType);
+//                                cmdFound = true;
+//                                if ((*it)->_cmdType == RdWebServerCmdDef::CMD_CALLBACK)
+//                                {
+//                                    char* respStr = ((*it)->_callback)(cmdStr, argStr);
+//                                    client.send(respStr, strlen(respStr));
+//                                }
+//                                else if ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE)
+//                                {
+//                                    if ((*it)->_substFileName[0] != '\0')
+//                                        handleLocalFileRequest((*it)->_substFileName, argStr, &client, httpHeader, (*it)->_bCacheIfPossible);
+//                                    else
+//                                        handleLocalFileRequest(cmdStr, argStr, &client, httpHeader, (*it)->_bCacheIfPossible);
+//                                }
+//                                else if ((*it)->_cmdType == RdWebServerCmdDef::CMD_SDORUSBFILE)
+//                                {
+//                                    if ((*it)->_substFileName[0] != '\0')
+//                                        handleSDFileRequest((*it)->_substFileName, argStr, &client, httpHeader);
+//                                    else
+//                                        handleSDFileRequest(cmdStr, argStr, &client, httpHeader);
+//                                }
+//                                break;
+//                            }
+//                        }
+//                        // If command not found see if it is a local file
+//                        if (!cmdFound)
+//                            handleLocalFileRequest(cmdStr, argStr, &client, httpHeader, false);
+//                    }
+//
+//                    break;
+//                }
+//                
+//            }
+//            pc.printf("Connection closed ... TCP server is listening...\r\n");
+//            client.close();
+//            if (_pStatusLed != NULL)
+//                *_pStatusLed = false;
+//        }
+//    }
+}
+
+void RdWebServer::addCommand(char* pCmdStr, int cmdType, CmdCallbackType callback, char* substFileName, bool cacheIfPossible)
+{
+    _commands.push_back(new RdWebServerCmdDef(pCmdStr, cmdType, callback, substFileName, cacheIfPossible));
+}
+
+void RdWebServer::handleSDFileRequest(char* inFileName, char* argStr, TCPSocketConnection &client, char* httpHeader)
+{
+    const int HTTPD_MAX_FNAME_LENGTH = 127;
+    char filename[HTTPD_MAX_FNAME_LENGTH+1];
+    
+    pc.printf("Requesting file %s\n\r", inFileName);
+    
+    char *lstchr = strrchr(inFileName, NULL) -1;
+    if ('/' == *lstchr)
+    {
+        pc.printf("Request file %s%s\n", _pBaseWebFolder, inFileName);
+        *lstchr = 0;
+        sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
+        DIR *d = opendir(filename);
+        if (d != NULL) {
+            sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
+            client.send(httpHeader,strlen(httpHeader));
+            sprintf(httpHeader,"<html><head><title>Directory Listing</title></head><body><h1>%s</h1><ul>", inFileName);
+            client.send(httpHeader,strlen(httpHeader));
+            struct dirent *p;
+            while((p = readdir(d)) != NULL) {
+                pc.printf("%s\n", p->d_name);
+                sprintf(httpHeader,"<li>%s</li>", p->d_name);
+                client.send(httpHeader,strlen(httpHeader));
+            }
+        }
+        closedir(d);
+        // pc.printf("Directory closed\n");
+        sprintf(httpHeader,"</ul></body></html>");
+        client.send(httpHeader,strlen(httpHeader));
+    }
+    else
+    {
+        sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
+        pc.printf ("Filename %s\r\n", filename);
+            
+        FILE* fp = fopen(filename, "r");
+        if (fp == NULL)
+        {
+            pc.printf ("Filename %s not found\r\n", filename);
+            sprintf(httpHeader,"HTTP/1.1 404 Not Found \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
+            client.send(httpHeader,strlen(httpHeader));
+            client.send(inFileName,strlen(inFileName));
+        }
+        else
+        {
+            pc.printf ("Sending file %s\r\n", filename);
+            sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
+            client.send(httpHeader,strlen(httpHeader));
+            int rdCnt = 0;
+            char fileBuf[1024];
+            while ((rdCnt = fread(fileBuf, sizeof( char ), 1024, fp)) == 1024) 
+            {
+                client.send(fileBuf, rdCnt);
+            }
+            client.send(fileBuf, rdCnt);
+            fclose(fp);
+        }
+    }
+//    FILE* fp = fopen("/sd/index.htm", "r");
+//    if (fp == NULL)
+//    {
+//        pc.printf ("Filename %s not found\r\n", inFileName);
+//    }
+//    else
+//    {
+//        pc.printf ("Sending file %s\r\n", inFileName);
+//        fclose(fp);
+//    }
+    
+//    const char * msg = "Hello World\n\r\n\r";
+//    sprintf(_buffer,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text/html\n\rConnection: Close\n\r\n\r", strlen(msg));
+//    client.send(_buffer,strlen(_buffer));
+//    client.send( const_cast<char*>(msg), strlen(msg));
+}
+
+void RdWebServer::sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection &client, char* httpHeader)
+{
+    pc.printf ("Sending file %s from cache %d bytes\r\n", pCacheEntry->_fileName, pCacheEntry->_nFileLen);
+    sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
+    client.send(httpHeader,strlen(httpHeader));
+    char* pMem = pCacheEntry->_pFileContent;
+    int nLenLeft = pCacheEntry->_nFileLen;
+    int blkSize = 2048;
+    while(nLenLeft > 0)
+    {
+        if (blkSize > nLenLeft)
+            blkSize = nLenLeft;
+        client.send_all(pMem, blkSize);
+        pMem += blkSize;
+        nLenLeft -= blkSize;
+    }
+}
+
+void RdWebServer::handleLocalFileRequest(char* inFileName, char* argStr, TCPSocketConnection &client, char* httpHeader, bool bCacheIfPossible)
+{
+    const int HTTPD_MAX_FNAME_LENGTH = 127;
+    char localFilename[HTTPD_MAX_FNAME_LENGTH+1];
+    char reqFileNameStr[HTTPD_MAX_FNAME_LENGTH+1];
+
+    pc.printf("Requesting local file %s\n\r", inFileName);
+    sprintf(reqFileNameStr, "/%s", inFileName);
+    sprintf(localFilename, "/local/%s", inFileName);
+        
+    if (bCacheIfPossible)
+    {
+        // Check if file already cached
+        bool bTryToCache = true;
+        for (std::vector<RdFileCacheEntry*>::iterator it = _cachedFiles.begin() ; it != _cachedFiles.end(); ++it)
+        {
+            if (strcmp(inFileName, (*it)->_fileName) == 0)
+            {
+                if ((*it)->_bCacheValid)
+                {
+                    sendFromCache(*it, client, httpHeader);
+                    return;
+                }
+                bTryToCache = false; // don't try to cache as cacheing must have already failed
+            }
+        }
+        
+        // See if we can cache the file
+        if (bTryToCache)
+        {
+            RdFileCacheEntry* pCacheEntry = new RdFileCacheEntry(inFileName);
+            if (pCacheEntry)
+            {
+                bool bCacheSuccess = pCacheEntry->readLocalFileIntoCache(localFilename);
+                // Store the cache entry even if reading failed (mem alloc or file not found, etc) so we don't try to cache again
+                _cachedFiles.push_back(pCacheEntry);
+                if (bCacheSuccess)
+                {
+                    sendFromCache(pCacheEntry, client, httpHeader);
+                    return;
+                }
+            }
+        }        
+    }
+    
+    LocalFileSystem local("local");
+    
+    FILE* fp = fopen(localFilename, "r");
+    if (fp == NULL)
+    {
+        pc.printf ("Local file %s not found\r\n", localFilename);
+        sprintf(httpHeader,"HTTP/1.1 404 Not Found \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
+        client.send(httpHeader,strlen(httpHeader));
+        client.send(reqFileNameStr,strlen(reqFileNameStr));
+    }
+    else
+    {
+        pc.printf ("Sending file %s from disk\r\n", localFilename);
+        sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
+        client.send(httpHeader,strlen(httpHeader));
+        int rdCnt = 0;
+        char fileBuf[2000];
+        while ((rdCnt = fread(fileBuf, sizeof( char ), 2000, fp)) == 2000) 
+        {
+            client.send_all(fileBuf, rdCnt);
+        }
+        client.send_all(fileBuf, rdCnt);
+        fclose(fp);
+    }
+}
+
+bool RdFileCacheEntry::readLocalFileIntoCache(char* fileName)
+{
+    pc.printf("Reading into cache %s\n\r", fileName);
+    LocalFileSystem local("local");
+    FILE* fp = fopen(fileName, "r");
+    if (fp == NULL)
+    {
+        pc.printf("Failed to open file\n\r");
+        return false;
+    }
+    pc.printf("Seeking\n\r");
+    fseek(fp, 0, SEEK_END);
+    _nFileLen = (int)ftell(fp);
+    _pFileContent = new char[_nFileLen];
+    pc.printf("Len %d Buf %08x\n\r", _nFileLen, _pFileContent);
+    if (!_pFileContent)
+    {
+        pc.printf("Failed to allocate %lu\n\r", _nFileLen);
+        fclose(fp);
+        return false;
+    }
+    pc.printf("Allocated\n\r");
+    memset(_pFileContent, 0, _nFileLen);
+    fseek(fp, 0, SEEK_SET);
+    char* pMem = _pFileContent;
+    char fileBuf[100];
+    int totCnt = 0;
+    int rdCnt = 0;
+    pc.printf("Reading\n\r");
+    while (true)
+    {
+        int toRead = _nFileLen - totCnt;
+        if (toRead > sizeof(fileBuf))
+            toRead = sizeof(fileBuf);
+        if (toRead <= 0)
+            break;
+        rdCnt = fread(fileBuf, sizeof(char), toRead, fp);
+        if (rdCnt <= 0)
+            break;
+        pc.printf("Read %d tot %d of %d\n\r", rdCnt, totCnt, _nFileLen);
+        memcpy(pMem, fileBuf, rdCnt);
+        pMem += rdCnt;
+        totCnt += rdCnt;
+    }
+    pc.printf("Done read\n\r");
+    fclose(fp);
+    pc.printf("Success in caching %d bytes (read %d)\n\r", _nFileLen, totCnt);
+    _bCacheValid = true;
     return true;
 }
 
@@ -144,259 +530,3 @@
     }
     return true;
 }
-
-void RdWebServer::sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection* pClient, char* httpHeader)
-{
-    printf ("Sending file %s from cache %d bytes\r\n", pCacheEntry->_fileName, pCacheEntry->_nFileLen);
-    sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
-    pClient->send(httpHeader,strlen(httpHeader));
-    char* pMem = pCacheEntry->_pFileContent;
-    int nLenLeft = pCacheEntry->_nFileLen;
-    int blkSize = 2048;
-    while(nLenLeft > 0)
-    {
-        if (blkSize > nLenLeft)
-            blkSize = nLenLeft;
-        pClient->send_all(pMem, blkSize);
-        pMem += blkSize;
-        nLenLeft -= blkSize;
-    }
-}
-
-void RdWebServer::handleLocalFileRequest(char* inFileName, char* argStr, TCPSocketConnection* pClient, char* httpHeader, bool bCacheIfPossible)
-{
-    const int HTTPD_MAX_FNAME_LENGTH = 127;
-    char localFilename[HTTPD_MAX_FNAME_LENGTH+1];
-    char reqFileNameStr[HTTPD_MAX_FNAME_LENGTH+1];
-
-    printf("Requesting local file %s\n\r", inFileName);
-    sprintf(reqFileNameStr, "/%s", inFileName);
-    sprintf(localFilename, "/local/%s", inFileName);
-        
-    if (bCacheIfPossible)
-    {
-        // Check if file already cached
-        bool bTryToCache = true;
-        for (std::vector<RdFileCacheEntry*>::iterator it = _cachedFiles.begin() ; it != _cachedFiles.end(); ++it)
-        {
-            if (strcmp(inFileName, (*it)->_fileName) == 0)
-            {
-                if ((*it)->_bCacheValid)
-                {
-                    sendFromCache(*it, pClient, httpHeader);
-                    return;
-                }
-                bTryToCache = false; // don't try to cache as cacheing must have already failed
-            }
-        }
-        
-        // See if we can cache the file
-        if (bTryToCache)
-        {
-            RdFileCacheEntry* pCacheEntry = new RdFileCacheEntry(inFileName);
-            if (pCacheEntry)
-            {
-                bool bCacheSuccess = pCacheEntry->readLocalFileIntoCache(localFilename);
-                // Store the cache entry even if reading failed (mem alloc or file not found, etc) so we don't try to cache again
-                _cachedFiles.push_back(pCacheEntry);
-                if (bCacheSuccess)
-                {
-                    sendFromCache(pCacheEntry, pClient, httpHeader);
-                    return;
-                }
-            }
-        }        
-    }
-    
-    LocalFileSystem local("local");
-    
-    FILE* fp = fopen(localFilename, "r");
-    if (fp == NULL)
-    {
-        printf ("Local file %s not found\r\n", localFilename);
-        sprintf(httpHeader,"HTTP/1.1 404 Not Found \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
-        pClient->send(httpHeader,strlen(httpHeader));
-        pClient->send(reqFileNameStr,strlen(reqFileNameStr));
-    }
-    else
-    {
-        printf ("Sending file %s from disk\r\n", localFilename);
-        sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
-        pClient->send(httpHeader,strlen(httpHeader));
-        int rdCnt = 0;
-        char fileBuf[2000];
-        while ((rdCnt = fread(fileBuf, sizeof( char ), 2000, fp)) == 2000) 
-        {
-            pClient->send_all(fileBuf, rdCnt);
-        }
-        pClient->send_all(fileBuf, rdCnt);
-        fclose(fp);
-    }
-}
-
-void RdWebServer::handleSDFileRequest(char* inFileName, char* argStr, TCPSocketConnection* pClient, char* httpHeader)
-{
-    const int HTTPD_MAX_FNAME_LENGTH = 127;
-    char filename[HTTPD_MAX_FNAME_LENGTH+1];
-    
-    printf("Requesting file %s\n\r", inFileName);
-    
-    char *lstchr = strrchr(inFileName, NULL) -1;
-    if ('/' == *lstchr)
-    {
-        printf("Request file %s%s\n", _pBaseWebFolder, inFileName);
-        *lstchr = 0;
-        sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
-        DIR *d = opendir(filename);
-        if (d != NULL) {
-            sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
-            pClient->send(httpHeader,strlen(httpHeader));
-            sprintf(httpHeader,"<html><head><title>Directory Listing</title></head><body><h1>%s</h1><ul>", inFileName);
-            pClient->send(httpHeader,strlen(httpHeader));
-            struct dirent *p;
-            while((p = readdir(d)) != NULL) {
-                printf("%s\n", p->d_name);
-                sprintf(httpHeader,"<li>%s</li>", p->d_name);
-                pClient->send(httpHeader,strlen(httpHeader));
-            }
-        }
-        closedir(d);
-        // printf("Directory closed\n");
-        sprintf(httpHeader,"</ul></body></html>");
-        pClient->send(httpHeader,strlen(httpHeader));
-    }
-    else
-    {
-        sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
-        printf ("Filename %s\r\n", filename);
-        FILE* fp = fopen(filename, "r");
-        if (fp == NULL)
-        {
-            printf ("Filename %s not found\r\n", filename);
-            sprintf(httpHeader,"HTTP/1.1 404 Not Found \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
-            pClient->send(httpHeader,strlen(httpHeader));
-            pClient->send(inFileName,strlen(inFileName));
-        }
-        else
-        {
-            printf ("Sending file %s\r\n", filename);
-            sprintf(httpHeader,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n");
-            pClient->send(httpHeader,strlen(httpHeader));
-            int rdCnt = 0;
-            char fileBuf[1024];
-            while ((rdCnt = fread(fileBuf, sizeof( char ), 1024, fp)) == 1024) 
-            {
-                pClient->send(fileBuf, rdCnt);
-            }
-            pClient->send(fileBuf, rdCnt);
-            fclose(fp);
-        }
-    }
-}
-
-void RdWebServer::run()
-{
-    TCPSocketConnection client;
-    const int HTTPD_MAX_HDR_LENGTH = 255;
-    char httpHeader[HTTPD_MAX_HDR_LENGTH+1];
-    const int HTTPD_MAX_REQ_LENGTH = 1023;
-    char buffer[HTTPD_MAX_REQ_LENGTH+1];
-    
-    //listening for http GET request
-    while (isListening())
-    {
-        //blocking mode(never timeout)
-        if(_socketSrv.accept(client)<0) 
-        {
-            printf("TCP Socket failed to accept connection\n\r");
-        }
-        else
-        {
-            client.set_blocking(false, 1000);
-            printf("Connection from IP: %s\n\r",client.get_address());
-            if (_pStatusLed != NULL)
-                *_pStatusLed = true;
-            Timer connectLimitTimer;
-            connectLimitTimer.start();
-            
-            while(connectLimitTimer.read() < 5)  // 5 seconds timeout on HTTP operation
-            {
-                int rxLen = client.receive(buffer, 1023);
-                if (rxLen == -1)
-                {
-                    continue;
-                }
-                else if (rxLen == 0)
-                {
-                    printf("received buffer is empty.\n\r");
-                    break;                
-                }
-                else if (rxLen >= 1024)
-                {
-                    sprintf(httpHeader,"HTTP/1.1 413 Request Entity Too Large \r\nContent-Type: text\r\nConnection: Close\r\n\r\n");
-                    client.send(httpHeader,strlen(httpHeader));
-                    client.send(buffer, rxLen);
-                    break;
-                }
-                buffer[rxLen] = '\0';
-//                printf("Received Data: %d\n\r\n\r%.*s\n\r",strlen(buffer),strlen(buffer),buffer);
-                if (strncmp(buffer, "GET ", 4) == 0)
-                {
-//                    printf("GET request\n\r");
-                    char cmdStr[MAX_CMDSTR_LEN];
-                    char argStr[MAX_ARGSTR_LEN];
-                    if (extractCmdArgs(buffer+3, cmdStr, MAX_CMDSTR_LEN, argStr, MAX_ARGSTR_LEN))
-                    {
-                        printf("CmdStr %s\n\r", cmdStr);
-                        printf("ArgStr %s\n\r", argStr);
-                        bool cmdFound = false;
-                        for (std::vector<RdWebServerCmdDef*>::iterator it = _commands.begin() ; it != _commands.end(); ++it)
-                        {
-//                            printf("Testing <<%s>> with <<%s>>\r\n", (*it)->_pCmdStr, cmdStr);
-                            if (strcasecmp((*it)->_pCmdStr, cmdStr) == 0)
-                            {                                    
-                                printf("FoundCmd <%s> Type %d\n\r", cmdStr, (*it)->_cmdType);
-                                cmdFound = true;
-                                if ((*it)->_cmdType == RdWebServerCmdDef::CMD_CALLBACK)
-                                {
-                                    ((*it)->_callback)(cmdStr, argStr);
-                                }
-                                else if ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE)
-                                {
-                                    if ((*it)->_substFileName[0] != '\0')
-                                        handleLocalFileRequest((*it)->_substFileName, argStr, &client, httpHeader, (*it)->_bCacheIfPossible);
-                                    else
-                                        handleLocalFileRequest(cmdStr, argStr, &client, httpHeader, (*it)->_bCacheIfPossible);
-                                }
-                                else if ((*it)->_cmdType == RdWebServerCmdDef::CMD_SDORUSBFILE)
-                                {
-                                    if ((*it)->_substFileName[0] != '\0')
-                                        handleSDFileRequest((*it)->_substFileName, argStr, &client, httpHeader);
-                                    else
-                                        handleSDFileRequest(cmdStr, argStr, &client, httpHeader);
-                                }
-                                break;
-                            }
-                        }
-                        // If command not found see if it is a local file
-                        if (!cmdFound)
-                            handleLocalFileRequest(cmdStr, argStr, &client, httpHeader, false);
-                    }
-
-                    break;
-                }
-                
-            }
-            printf("Connection closed ... TCP server is listening...\r\n");
-            client.close();
-            if (_pStatusLed != NULL)
-                *_pStatusLed = false;
-        }
-    }
-}
-
-void RdWebServer::addCommand(char* pCmdStr, int cmdType, CmdCallbackType callback, char* substFileName, bool cacheIfPossible)
-{
-    _commands.push_back(new RdWebServerCmdDef(pCmdStr, cmdType, callback, substFileName, cacheIfPossible));
-}
-
--- a/RdWebServer.h	Tue Feb 03 12:08:12 2015 +0000
+++ b/RdWebServer.h	Fri Feb 06 14:17:47 2015 +0000
@@ -10,6 +10,8 @@
 #include "mbed.h"
 #include "EthernetInterface.h"
 
+extern RawSerial pc;
+
 class RdFileCacheEntry
 {
     public:
@@ -33,7 +35,7 @@
         int _nFileLen;
 };
 
-typedef void (*CmdCallbackType)(char*cmdStr, char* argStr);
+typedef char* (*CmdCallbackType)(char*cmdStr, char* argStr);
 
 class RdWebServerCmdDef
 {
@@ -61,6 +63,9 @@
         bool _bCacheIfPossible;
 };
 
+const int HTTPD_MAX_HDR_LENGTH = 255;
+const int HTTPD_MAX_REQ_LENGTH = 1023;
+
 class RdWebServer
 {
     public :
@@ -86,11 +91,14 @@
         std::vector<RdFileCacheEntry*> _cachedFiles;
         bool extractCmdArgs(char* buf, char* pCmdStr, int maxCmdStrLen, char* pArgStr, int maxArgStrLen);
         char* _pBaseWebFolder;
+        char _httpHeader[HTTPD_MAX_HDR_LENGTH+1];
+        char _buffer[HTTPD_MAX_REQ_LENGTH+1];
 
-        void handleLocalFileRequest(char* cmdStr, char* argStr, TCPSocketConnection* pClient, char* httpHeader, bool bCacheIfPossible);
-        void handleSDFileRequest(char* cmdStr, char* argStr, TCPSocketConnection* pClient, char* httpHeader);
+        void handleLocalFileRequest(char* cmdStr, char* argStr, TCPSocketConnection &client, char* httpHeader, bool bCacheIfPossible);
+        void handleSDFileRequest(char* cmdStr, char* argStr, TCPSocketConnection &client, char* httpHeader);
         void handleCGIRequest(char* pUriStr, char* pQueryStr);
-        void sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection* pClient, char* httpHeader);
+        void sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection &client, char* httpHeader);
+        void handleReceivedHttp(TCPSocketConnection &client);
 
 };