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

Dependents:   RdBlindsServer SpideyWallWeb RdGasUseMonitor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RdWebServer.h Source File

RdWebServer.h

00001 // RdWebServer - Simple Web Server for MBED
00002 // Copyright (C) Rob Dobson 2013-2015, MIT License
00003 // Inspired by Jasper Schuurmans multi-threaded web server for Netduino which now seems to have gone from ...
00004 // http://www.schuurmans.cc/multi-threaded-web-server-for-netduino-plus
00005 // More details at http://robdobson.com/2013/10/moving-my-window-shades-control-to-mbed/
00006 
00007 #ifndef RD_WEB_SERVER
00008 #define RD_WEB_SERVER
00009 
00010 #include "mbed.h"
00011 
00012 // Debug level
00013 #ifdef RDWEB_DEBUG 
00014 #if (RDWEB_DEBUG > 3)
00015 #define RD_DBG(x, ...) std::printf("[RD_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
00016 #else
00017 #define RD_DBG(x, ...)
00018 #endif
00019 #else
00020 #define RD_DBG(x, ...)
00021 #endif
00022 
00023 #ifdef RDWEB_DEBUG 
00024 #if (RDWEB_DEBUG > 2)
00025 #define RD_INFO(x, ...) std::printf("[RD_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
00026 #else
00027 #define RD_INFO(x, ...)
00028 #endif
00029 #else
00030 #define RD_INFO(x, ...)
00031 #endif
00032 
00033 #ifdef RDWEB_DEBUG 
00034 #if (RDWEB_DEBUG > 1)
00035 #define RD_WARN(x, ...) std::printf("[RD_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
00036 #else
00037 #define RD_WARN(x, ...)
00038 #endif
00039 #else
00040 #define RD_WARN(x, ...)
00041 #endif
00042 
00043 #ifdef RDWEB_DEBUG 
00044 #if (RDWEB_DEBUG > 0)
00045 #define RD_ERR(x, ...) std::printf("[RD_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
00046 #else
00047 #define RD_ERR(x, ...)
00048 #endif
00049 #else
00050 #define RD_ERR(x, ...)
00051 #endif
00052 
00053 // Length of strings
00054 const int MAX_CMDSTR_LEN = 100;
00055 const int MAX_ARGSTR_LEN = 100;
00056 const int MAX_WEB_SERVER_CMDS = 30;
00057 const int MAX_WEB_SERVER_CACHED_FILES = 5;
00058 const int SUBST_MAX_FNAME_LEN = 40;  // note local files on MBED are 8.3 but this might include other files
00059 
00060 extern RawSerial pc;
00061 
00062 class RdFileCacheEntry
00063 {
00064     public:
00065         RdFileCacheEntry(char* pFileName)
00066         {
00067             _bCacheValid = false;
00068             strncpy(_fileName, pFileName, SUBST_MAX_FNAME_LEN-1);
00069             _fileName[SUBST_MAX_FNAME_LEN-1] = '\0';
00070             _pFileContent = NULL;
00071         }
00072         ~RdFileCacheEntry()
00073         {
00074             delete _pFileContent;
00075         }
00076         bool readLocalFileIntoCache(char* fileName);
00077     public:
00078         bool _bCacheValid;
00079         char _fileName[SUBST_MAX_FNAME_LEN];
00080         char* _pFileContent;
00081         int _nFileLen;
00082 };
00083 
00084 typedef char* (*CmdCallbackType)(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
00085                 int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos);
00086 
00087 class RdWebServerCmdDef
00088 {
00089     public:
00090         static const int CMD_LOCALFILE = 1;
00091         static const int CMD_CALLBACK = 2;
00092         static const int CMD_SDORUSBFILE = 3;
00093         RdWebServerCmdDef(char* pStr, int cmdType, CmdCallbackType callback, char* substFileName = NULL, bool bCacheIfPossible = false)
00094         {
00095             _pCmdStr = pStr;
00096             _cmdType = cmdType;
00097             _callback = callback;
00098             _substFileName[0] = '\0';
00099             if (substFileName != NULL)
00100             {
00101                 strncpy(_substFileName, substFileName, SUBST_MAX_FNAME_LEN);
00102                 _substFileName[SUBST_MAX_FNAME_LEN-1] = '\0';
00103             }
00104             _bCacheIfPossible = bCacheIfPossible;
00105         };
00106         char* _pCmdStr;
00107         int _cmdType;
00108         CmdCallbackType _callback;
00109         char _substFileName[SUBST_MAX_FNAME_LEN];
00110         bool _bCacheIfPossible;
00111 };
00112 
00113 const int HTTPD_MAX_HDR_LENGTH = 255;
00114 // The FRDM-K64F has more memory than the LPC1768 so allow a larger buffer
00115 #if defined(MCU_MK64F12)
00116 const int HTTPD_MAX_REQ_LENGTH = 2048;
00117 #warning("TCP Request Length 2048")
00118 #elif defined(TARGET_ARCH_BLE)
00119 const int HTTPD_MAX_REQ_LENGTH = 1024;
00120 #warning("TCP Request Length 1024")
00121 #else
00122 const int HTTPD_MAX_REQ_LENGTH = 1024;
00123 #warning("TCP Request Length 1024")
00124 #endif
00125 
00126 class TCPSocketServer;
00127 class TCPSocketConnection;
00128 class rtos::Mutex;
00129 
00130 class RdWebServer
00131 {
00132     public :
00133         static const int METHOD_OTHER = 0;
00134         static const int METHOD_GET = 1;
00135         static const int METHOD_POST = 2;
00136         static const int METHOD_OPTIONS = 3;
00137         RdWebServer(TCPSocketServer& tcpServerSocket, rtos::Mutex* pSdCardMutex = NULL);
00138         virtual ~RdWebServer();
00139         
00140         bool init(int port, DigitalOut* pStatusLed, char* pBaseWebFolder);
00141         void run();
00142         void addCommand(char* pCmdStr, int cmdType, CmdCallbackType callback = NULL, char* substFileName = NULL, bool cacheIfPossible = false);
00143         
00144         static unsigned char* getPayloadDataFromMsg(char* msgBuf, int msgLen, int& payloadLen);
00145         static int getContentLengthFromMsg(char* msgBuf);
00146 
00147     private :
00148         int _port;
00149         DigitalOut* _pStatusLed;
00150         TCPSocketServer& _serverSocket;
00151         bool _initOk;
00152         RdWebServerCmdDef* _pWebServerCmds[MAX_WEB_SERVER_CMDS];
00153         int _numWebServerCmds;
00154         RdFileCacheEntry* _pWebServerCachedFiles[MAX_WEB_SERVER_CACHED_FILES];
00155         int _numWebServerCachedFiles;
00156         bool extractCmdArgs(char* buf, char* pCmdStr, int maxCmdStrLen, char* pArgStr, int maxArgStrLen, int& contentLen);
00157         char* _pBaseWebFolder;
00158         char _httpHeader[HTTPD_MAX_HDR_LENGTH+1];
00159         char _buffer[HTTPD_MAX_REQ_LENGTH+1];
00160         int _bufferReceivedLen;
00161 
00162         bool handleLocalFileRequest(char* cmdStr, char* argStr, TCPSocketConnection &client, bool bCacheIfPossible);
00163         bool handleSDFileRequest(char* cmdStr, char* argStr, TCPSocketConnection &client);
00164         void handleCGIRequest(char* pUriStr, char* pQueryStr);
00165         void sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection &client);
00166         bool handleReceivedHttp(TCPSocketConnection &client);
00167         void formHTTPHeader(const char* rsltCode, const char* contentType, int contentLen);
00168 
00169         // Settings - see the constructor
00170         bool _blockingOnAccept;
00171         bool _blockingOnReceive;
00172         int _timeoutOnBlocking;
00173         bool _closeConnAfterSend;
00174         bool _closeConnOnReceiveFail;
00175         
00176         // Handling of split payloads on receipt (e.g. POST)
00177         int _curSplitPayloadPos;
00178         char _curCmdStr[MAX_CMDSTR_LEN];
00179         char _curArgStr[MAX_ARGSTR_LEN];
00180         int _curContentLen;
00181         int _curHttpMethod;
00182         RdWebServerCmdDef* _curWebServerCmdDef;
00183         
00184         // Mutex for SD card access (if supplied in constructor)
00185         Mutex* _pSdCardMutex;
00186 };
00187 
00188 #endif