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.
Revision 7:fe7c33f7fbb8, committed 2015-02-07
- Comitter:
- Bobty
- Date:
- Sat Feb 07 10:34:09 2015 +0000
- Parent:
- 6:46285c519af2
- Child:
- 8:de915bd70ec1
- Commit message:
- Working with gas count - not tested on actual meter reed switch
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 Fri Feb 06 14:17:47 2015 +0000
+++ b/RdWebServer.cpp Sat Feb 07 10:34:09 2015 +0000
@@ -57,50 +57,52 @@
void RdWebServer::handleReceivedHttp(TCPSocketConnection &client)
{
- pc.printf("Received Data: %d\n\r\n\r%.*s\n\r",strlen(_buffer),strlen(_buffer),_buffer);
+// pc.printf("Received Data: %d\n\r\n\r%.*s\n\r",strlen(_buffer),strlen(_buffer),_buffer);
+ int method = METHOD_OTHER;
if (strncmp(_buffer, "GET ", 4) == 0)
+ method = METHOD_GET;
+ if (strncmp(_buffer, "POST", 4) == 0)
+ method = METHOD_POST;
+
+ char cmdStr[MAX_CMDSTR_LEN];
+ char argStr[MAX_ARGSTR_LEN];
+ if (extractCmdArgs(_buffer+3, cmdStr, MAX_CMDSTR_LEN, argStr, MAX_ARGSTR_LEN))
{
- 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("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;
+// 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)(method, 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);
}
+ // If command not found see if it is a local file
+ if (!cmdFound)
+ handleSDFileRequest(cmdStr, argStr, client, _httpHeader);
}
}
@@ -143,133 +145,8 @@
// 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)
@@ -336,21 +213,6 @@
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)
@@ -501,15 +363,17 @@
int argStrLen = 0;
if (buf == NULL)
return false;
+ // Check for first slash
char* pSlash1 = strchr(buf, '/');
if (pSlash1 == NULL)
return false;
pSlash1++;
+ // Extract command
while(*pSlash1)
{
if (cmdStrLen >= maxCmdStrLen-1)
break;
- if ((*pSlash1 == '/') || (*pSlash1 == ' ') || (*pSlash1 == '\n'))
+ if ((*pSlash1 == '/') || (*pSlash1 == ' ') || (*pSlash1 == '\n') || (*pSlash1 == '?') || (*pSlash1 == '&'))
break;
*pCmdStr++ = *pSlash1++;
*pCmdStr = '\0';
@@ -517,6 +381,7 @@
}
if ((*pSlash1 == '\0') || (*pSlash1 == ' ') || (*pSlash1 == '\n'))
return true;
+ // Now args
*pSlash1++;
while(*pSlash1)
{
--- a/RdWebServer.h Fri Feb 06 14:17:47 2015 +0000
+++ b/RdWebServer.h Sat Feb 07 10:34:09 2015 +0000
@@ -35,7 +35,7 @@
int _nFileLen;
};
-typedef char* (*CmdCallbackType)(char*cmdStr, char* argStr);
+typedef char* (*CmdCallbackType)(int method, char*cmdStr, char* argStr);
class RdWebServerCmdDef
{
@@ -69,7 +69,9 @@
class RdWebServer
{
public :
-
+ static const int METHOD_OTHER = 0;
+ static const int METHOD_GET = 1;
+ static const int METHOD_POST = 2;
RdWebServer();
virtual ~RdWebServer();