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.

Committer:
Bobty
Date:
Mon Sep 28 10:29:45 2015 +0000
Revision:
25:ffa1dddd3da4
Parent:
24:27800de38eab
Child:
26:3c4c10e989b1
Fix problem getting a file from SD card; Changed debug messages

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Bobty 20:e6c7db867593 1 // RdWebServer - Simple Web Server for MBED
Bobty 20:e6c7db867593 2 // Copyright (C) Rob Dobson 2013-2015, MIT License
Bobty 20:e6c7db867593 3 // Inspired by Jasper Schuurmans multi-threaded web server for Netduino which now seems to have gone from ...
Bobty 20:e6c7db867593 4 // http://www.schuurmans.cc/multi-threaded-web-server-for-netduino-plus
Bobty 20:e6c7db867593 5 // More details at http://robdobson.com/2013/10/moving-my-window-shades-control-to-mbed/
Bobty 3:594136d34a32 6
Bobty 18:5de680c4cfcb 7 // Setting RDWEB_DEBUG to 4 causes all debugging to be shown
Bobty 21:2dfb56648b93 8 #define RDWEB_DEBUG 2
Bobty 18:5de680c4cfcb 9
Bobty 18:5de680c4cfcb 10 // Change the settings below to support a local file system (not available on some MBEDs)
Bobty 21:2dfb56648b93 11 #define SUPPORT_LOCAL_FILESYSTEM 1
Bobty 21:2dfb56648b93 12 #define SUPPORT_LOCAL_FILE_CACHE 1
Bobty 18:5de680c4cfcb 13
Bobty 18:5de680c4cfcb 14 // Change this to support display of files on the server
Bobty 18:5de680c4cfcb 15 //#define SUPPORT_FOLDER_VIEW 1
Bobty 12:c14ffd4ec125 16
Bobty 0:b5b4d07f7827 17 #include "RdWebServer.h"
Bobty 0:b5b4d07f7827 18
Bobty 18:5de680c4cfcb 19 // Limits - note particularly the MAX_FILENAME_LEN
Bobty 15:0865fa4b046a 20 const int MAX_FILENAME_LEN = (MAX_ARGSTR_LEN + 20);
Bobty 1:75bb184de749 21
Bobty 18:5de680c4cfcb 22 // Constructor
Bobty 0:b5b4d07f7827 23 RdWebServer::RdWebServer()
Bobty 0:b5b4d07f7827 24 {
Bobty 15:0865fa4b046a 25 _initOk = false;
Bobty 0:b5b4d07f7827 26 _pStatusLed = NULL;
Bobty 24:27800de38eab 27 _curSplitPayloadPos = -1;
Bobty 24:27800de38eab 28 _curCmdStr[0] = 0;
Bobty 24:27800de38eab 29 _curArgStr[0] = 0;
Bobty 24:27800de38eab 30 _bufferReceivedLen = 0;
Bobty 24:27800de38eab 31 _curContentLen = -1;
Bobty 24:27800de38eab 32 _curHttpMethod = METHOD_OTHER;
Bobty 24:27800de38eab 33 _curWebServerCmdDef = NULL;
Bobty 0:b5b4d07f7827 34 }
Bobty 0:b5b4d07f7827 35
Bobty 18:5de680c4cfcb 36 // Destructor
Bobty 0:b5b4d07f7827 37 RdWebServer::~RdWebServer()
Bobty 0:b5b4d07f7827 38 {
Bobty 2:9d8793c23b46 39 // Clean-up - probably never called as we're on a microcontroller!
Bobty 2:9d8793c23b46 40 for (std::vector<RdWebServerCmdDef*>::iterator it = _commands.begin() ; it != _commands.end(); ++it)
Bobty 2:9d8793c23b46 41 delete (*it);
Bobty 0:b5b4d07f7827 42 }
Bobty 0:b5b4d07f7827 43
Bobty 18:5de680c4cfcb 44 // Init
Bobty 4:6afb3bbf20a4 45 bool RdWebServer::init(int port, DigitalOut* pStatusLed, char* pBaseWebFolder)
Bobty 0:b5b4d07f7827 46 {
Bobty 15:0865fa4b046a 47 // Settings
Bobty 0:b5b4d07f7827 48 _port = port;
Bobty 0:b5b4d07f7827 49 _pStatusLed = pStatusLed;
Bobty 4:6afb3bbf20a4 50 _pBaseWebFolder = pBaseWebFolder;
Bobty 0:b5b4d07f7827 51
Bobty 23:0fc3d7b5e596 52 // Non-blocking by default
Bobty 23:0fc3d7b5e596 53 _blockingOnAccept = false;
Bobty 23:0fc3d7b5e596 54 _blockingOnReceive = false;
Bobty 17:080f2bed8b36 55
Bobty 17:080f2bed8b36 56 // This is the same as the default in the socket.cpp file
Bobty 17:080f2bed8b36 57 _timeoutOnBlocking = 1500;
Bobty 17:080f2bed8b36 58
Bobty 17:080f2bed8b36 59 // If closeConnAfterSend is set false then the socket connection remains open and only
Bobty 23:0fc3d7b5e596 60 // one client can access the server until a time-out occurs - this should be ok for most applications
Bobty 23:0fc3d7b5e596 61 _closeConnAfterSend = false;
Bobty 17:080f2bed8b36 62 _closeConnOnReceiveFail = true;
Bobty 17:080f2bed8b36 63
Bobty 15:0865fa4b046a 64 // Setup tcp socket
Bobty 15:0865fa4b046a 65 if(_serverSocket.bind(port)< 0)
Bobty 0:b5b4d07f7827 66 {
Bobty 19:f67ac231b570 67 RD_WARN("TCP server bind fail");
Bobty 0:b5b4d07f7827 68 return false;
Bobty 0:b5b4d07f7827 69 }
Bobty 23:0fc3d7b5e596 70
Bobty 23:0fc3d7b5e596 71 // Only one connection at a time as the server is single-threaded
Bobty 15:0865fa4b046a 72 if(_serverSocket.listen(1) < 0)
Bobty 0:b5b4d07f7827 73 {
Bobty 19:f67ac231b570 74 RD_WARN("TCP server listen fail");
Bobty 0:b5b4d07f7827 75 return false;
Bobty 0:b5b4d07f7827 76 }
Bobty 19:f67ac231b570 77 RD_INFO("TCP server is listening...");
Bobty 15:0865fa4b046a 78 _initOk = true;
Bobty 6:46285c519af2 79 return true;
Bobty 6:46285c519af2 80 }
Bobty 6:46285c519af2 81
Bobty 18:5de680c4cfcb 82 // Run - never returns so run in a thread
Bobty 15:0865fa4b046a 83 void RdWebServer::run()
Bobty 15:0865fa4b046a 84 {
Bobty 15:0865fa4b046a 85 // Check initialised ok
Bobty 15:0865fa4b046a 86 if (!_initOk)
Bobty 15:0865fa4b046a 87 return;
Bobty 15:0865fa4b046a 88
Bobty 15:0865fa4b046a 89 // Start accepting connections
Bobty 15:0865fa4b046a 90 while (true)
Bobty 15:0865fa4b046a 91 {
Bobty 15:0865fa4b046a 92 TCPSocketConnection clientSocketConn;
Bobty 15:0865fa4b046a 93 // Accept connection if available
Bobty 19:f67ac231b570 94 RD_INFO("Waiting for TCP connection");
Bobty 17:080f2bed8b36 95 clientSocketConn.set_blocking(_blockingOnAccept, _timeoutOnBlocking);
Bobty 15:0865fa4b046a 96 if(_serverSocket.accept(clientSocketConn)<0)
Bobty 15:0865fa4b046a 97 {
Bobty 19:f67ac231b570 98 RD_WARN("TCP Socket failed to accept connection");
Bobty 15:0865fa4b046a 99 continue;
Bobty 15:0865fa4b046a 100 }
Bobty 15:0865fa4b046a 101
Bobty 15:0865fa4b046a 102 // Connection
Bobty 19:f67ac231b570 103 RD_INFO("Connection from IP: %s", clientSocketConn.get_address());
Bobty 15:0865fa4b046a 104 if (_pStatusLed != NULL)
Bobty 15:0865fa4b046a 105 *_pStatusLed = true;
Bobty 15:0865fa4b046a 106
Bobty 15:0865fa4b046a 107 // While connected
Bobty 15:0865fa4b046a 108 bool forcedClosed = false;
Bobty 24:27800de38eab 109 _curSplitPayloadPos = -1;
Bobty 15:0865fa4b046a 110 while(clientSocketConn.is_connected() && !forcedClosed)
Bobty 15:0865fa4b046a 111 {
Bobty 15:0865fa4b046a 112 // Receive data
Bobty 23:0fc3d7b5e596 113 if (_blockingOnReceive != _blockingOnAccept)
Bobty 23:0fc3d7b5e596 114 clientSocketConn.set_blocking(_blockingOnReceive, _timeoutOnBlocking);
Bobty 15:0865fa4b046a 115 int rxLen = clientSocketConn.receive(_buffer, HTTPD_MAX_REQ_LENGTH);
Bobty 15:0865fa4b046a 116 if (rxLen == -1)
Bobty 15:0865fa4b046a 117 {
Bobty 17:080f2bed8b36 118 if (_closeConnOnReceiveFail)
Bobty 15:0865fa4b046a 119 {
Bobty 15:0865fa4b046a 120 int closeRet = clientSocketConn.close();
Bobty 25:ffa1dddd3da4 121 RD_DBG("Rx Timeout - conn close() ret %d (is_connected %d)", closeRet, clientSocketConn.is_connected());
Bobty 15:0865fa4b046a 122 forcedClosed = true;
Bobty 15:0865fa4b046a 123 }
Bobty 25:ffa1dddd3da4 124 else
Bobty 25:ffa1dddd3da4 125 {
Bobty 25:ffa1dddd3da4 126 RD_DBG("Rx Timeout - not closing - is_connected %d", clientSocketConn.is_connected());
Bobty 25:ffa1dddd3da4 127 }
Bobty 15:0865fa4b046a 128 continue;
Bobty 15:0865fa4b046a 129 }
Bobty 15:0865fa4b046a 130 if (rxLen == 0)
Bobty 15:0865fa4b046a 131 {
Bobty 19:f67ac231b570 132 RD_DBG("clientSocketConn.receive() returned %d - ignoring - is connected %d", rxLen, clientSocketConn.is_connected());
Bobty 15:0865fa4b046a 133 continue;
Bobty 15:0865fa4b046a 134 }
Bobty 18:5de680c4cfcb 135
Bobty 18:5de680c4cfcb 136 // Handle received message
Bobty 15:0865fa4b046a 137 _buffer[rxLen] = '\0';
Bobty 24:27800de38eab 138 _bufferReceivedLen = rxLen;
Bobty 24:27800de38eab 139 handleReceivedHttp(clientSocketConn);
Bobty 15:0865fa4b046a 140
Bobty 17:080f2bed8b36 141 // Close connection if required
Bobty 17:080f2bed8b36 142 if (_closeConnAfterSend)
Bobty 15:0865fa4b046a 143 {
Bobty 15:0865fa4b046a 144 int closeRet = clientSocketConn.close();
Bobty 19:f67ac231b570 145 RD_DBG("After send connection close() ret %d is connected %d", closeRet, clientSocketConn.is_connected());
Bobty 16:0248bbfdb6c1 146 forcedClosed = true;
Bobty 15:0865fa4b046a 147 }
Bobty 15:0865fa4b046a 148 }
Bobty 15:0865fa4b046a 149 }
Bobty 15:0865fa4b046a 150 }
Bobty 18:5de680c4cfcb 151
Bobty 18:5de680c4cfcb 152 // Handle a request
Bobty 15:0865fa4b046a 153 bool RdWebServer::handleReceivedHttp(TCPSocketConnection &clientSocketConn)
Bobty 6:46285c519af2 154 {
Bobty 17:080f2bed8b36 155 bool handledOk = false;
Bobty 24:27800de38eab 156
Bobty 24:27800de38eab 157 // Check for split payload
Bobty 24:27800de38eab 158 if (_curSplitPayloadPos != -1)
Bobty 24:27800de38eab 159 {
Bobty 24:27800de38eab 160 // Handle remaining parts of content
Bobty 24:27800de38eab 161 char* respStr = (_curWebServerCmdDef->_callback)(_curHttpMethod, _curCmdStr, _curArgStr, _buffer, _bufferReceivedLen,
Bobty 24:27800de38eab 162 _curContentLen, (unsigned char*)_buffer, _bufferReceivedLen, _curSplitPayloadPos);
Bobty 24:27800de38eab 163 RD_DBG("Received part of message - content %d - rx %d - splitAfter %d", _curContentLen, _bufferReceivedLen, _curSplitPayloadPos);
Bobty 24:27800de38eab 164 _curSplitPayloadPos += _bufferReceivedLen;
Bobty 24:27800de38eab 165 // Check if all received
Bobty 24:27800de38eab 166 if (_curSplitPayloadPos >= _curContentLen)
Bobty 24:27800de38eab 167 {
Bobty 24:27800de38eab 168 _curSplitPayloadPos = -1;
Bobty 24:27800de38eab 169 clientSocketConn.send_all(respStr, strlen(respStr));
Bobty 24:27800de38eab 170 RD_DBG("That was the end of message - content %d - rx %d", _curContentLen, _bufferReceivedLen);
Bobty 24:27800de38eab 171 }
Bobty 24:27800de38eab 172 return true;
Bobty 24:27800de38eab 173 }
Bobty 24:27800de38eab 174
Bobty 24:27800de38eab 175 // Get payload information
Bobty 24:27800de38eab 176 int payloadLen = -1;
Bobty 24:27800de38eab 177 unsigned char* pPayload = getPayloadDataFromMsg(_buffer, _bufferReceivedLen, payloadLen);
Bobty 24:27800de38eab 178
Bobty 24:27800de38eab 179 // Debug
Bobty 24:27800de38eab 180 int displayLen = _bufferReceivedLen;
Bobty 24:27800de38eab 181 if (payloadLen > 0)
Bobty 24:27800de38eab 182 displayLen = _bufferReceivedLen-payloadLen;
Bobty 24:27800de38eab 183 RD_DBG("\r\nNEW REQUEST RxLen %d ContentLen %d PayloadLen %d\n\r\n\r%.*s", _bufferReceivedLen, _curContentLen, payloadLen, displayLen, _buffer);
Bobty 24:27800de38eab 184
Bobty 24:27800de38eab 185 // Get HTTP method
Bobty 24:27800de38eab 186 _curHttpMethod = METHOD_OTHER;
Bobty 6:46285c519af2 187 if (strncmp(_buffer, "GET ", 4) == 0)
Bobty 24:27800de38eab 188 _curHttpMethod = METHOD_GET;
Bobty 23:0fc3d7b5e596 189 else if (strncmp(_buffer, "POST", 4) == 0)
Bobty 24:27800de38eab 190 _curHttpMethod = METHOD_POST;
Bobty 23:0fc3d7b5e596 191 else if (strncmp(_buffer, "OPTIONS", 7) == 0)
Bobty 24:27800de38eab 192 _curHttpMethod = METHOD_OPTIONS;
Bobty 7:fe7c33f7fbb8 193
Bobty 24:27800de38eab 194 // See if there is a valid HTTP command
Bobty 24:27800de38eab 195 _curContentLen = -1;
Bobty 24:27800de38eab 196 if (extractCmdArgs(_buffer+3, _curCmdStr, MAX_CMDSTR_LEN, _curArgStr, MAX_ARGSTR_LEN, _curContentLen))
Bobty 6:46285c519af2 197 {
Bobty 24:27800de38eab 198 RD_DBG("CmdStr %s", _curCmdStr);
Bobty 24:27800de38eab 199 RD_DBG("ArgStr %s", _curArgStr);
Bobty 24:27800de38eab 200
Bobty 7:fe7c33f7fbb8 201 bool cmdFound = false;
Bobty 7:fe7c33f7fbb8 202 for (std::vector<RdWebServerCmdDef*>::iterator it = _commands.begin() ; it != _commands.end(); ++it)
Bobty 6:46285c519af2 203 {
Bobty 24:27800de38eab 204 if (strcasecmp((*it)->_pCmdStr, _curCmdStr) == 0)
Bobty 24:27800de38eab 205 {
Bobty 24:27800de38eab 206 RD_DBG("FoundCmd <%s> Type %d", _curCmdStr, (*it)->_cmdType);
Bobty 7:fe7c33f7fbb8 207 cmdFound = true;
Bobty 7:fe7c33f7fbb8 208 if ((*it)->_cmdType == RdWebServerCmdDef::CMD_CALLBACK)
Bobty 7:fe7c33f7fbb8 209 {
Bobty 24:27800de38eab 210 char* respStr = ((*it)->_callback)(_curHttpMethod, _curCmdStr, _curArgStr, _buffer, _bufferReceivedLen,
Bobty 24:27800de38eab 211 _curContentLen, pPayload, payloadLen, 0);
Bobty 24:27800de38eab 212 // Handle split-payload situation
Bobty 24:27800de38eab 213 if (_curContentLen > 0 && payloadLen < _curContentLen)
Bobty 24:27800de38eab 214 {
Bobty 24:27800de38eab 215 _curSplitPayloadPos = payloadLen;
Bobty 24:27800de38eab 216 _curWebServerCmdDef = (*it);
Bobty 24:27800de38eab 217 }
Bobty 24:27800de38eab 218 else
Bobty 24:27800de38eab 219 {
Bobty 24:27800de38eab 220 clientSocketConn.send_all(respStr, strlen(respStr));
Bobty 24:27800de38eab 221 }
Bobty 24:27800de38eab 222 handledOk = true;
Bobty 6:46285c519af2 223 }
Bobty 17:080f2bed8b36 224 else if ( ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE) ||
Bobty 17:080f2bed8b36 225 ((*it)->_cmdType == RdWebServerCmdDef::CMD_SDORUSBFILE) )
Bobty 7:fe7c33f7fbb8 226 {
Bobty 17:080f2bed8b36 227 char combinedFileName[MAX_FILENAME_LEN];
Bobty 17:080f2bed8b36 228 strcpy(combinedFileName, (*it)->_substFileName);
Bobty 17:080f2bed8b36 229 if (strlen(combinedFileName) == 0)
Bobty 24:27800de38eab 230 strcpy(combinedFileName, _curCmdStr);
Bobty 17:080f2bed8b36 231 else if (combinedFileName[strlen(combinedFileName)-1] == '*')
Bobty 24:27800de38eab 232 strcpy(combinedFileName+strlen(combinedFileName)-1, _curArgStr);
Bobty 17:080f2bed8b36 233 if ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE)
Bobty 24:27800de38eab 234 handledOk = handleLocalFileRequest(combinedFileName, _curArgStr, clientSocketConn, (*it)->_bCacheIfPossible);
Bobty 7:fe7c33f7fbb8 235 else
Bobty 24:27800de38eab 236 handledOk = handleSDFileRequest(combinedFileName, _curArgStr, clientSocketConn);
Bobty 17:080f2bed8b36 237
Bobty 7:fe7c33f7fbb8 238 }
Bobty 7:fe7c33f7fbb8 239 break;
Bobty 6:46285c519af2 240 }
Bobty 6:46285c519af2 241 }
Bobty 7:fe7c33f7fbb8 242 // If command not found see if it is a local file
Bobty 7:fe7c33f7fbb8 243 if (!cmdFound)
Bobty 17:080f2bed8b36 244 {
Bobty 17:080f2bed8b36 245 char combinedFileName[MAX_FILENAME_LEN];
Bobty 24:27800de38eab 246 strcpy(combinedFileName, _curCmdStr);
Bobty 25:ffa1dddd3da4 247 if (strlen(_curArgStr) > 0)
Bobty 25:ffa1dddd3da4 248 {
Bobty 25:ffa1dddd3da4 249 strcat(combinedFileName, "/");
Bobty 25:ffa1dddd3da4 250 strcat(combinedFileName, _curArgStr);
Bobty 25:ffa1dddd3da4 251 }
Bobty 24:27800de38eab 252 handledOk = handleSDFileRequest(combinedFileName, _curArgStr, clientSocketConn);
Bobty 17:080f2bed8b36 253 }
Bobty 6:46285c519af2 254 }
Bobty 24:27800de38eab 255 else
Bobty 24:27800de38eab 256 {
Bobty 24:27800de38eab 257 RD_DBG("Cannot find command or args\r\n");
Bobty 24:27800de38eab 258 }
Bobty 17:080f2bed8b36 259 return handledOk;
Bobty 6:46285c519af2 260 }
Bobty 6:46285c519af2 261
Bobty 18:5de680c4cfcb 262 // Add a command to the server
Bobty 6:46285c519af2 263 void RdWebServer::addCommand(char* pCmdStr, int cmdType, CmdCallbackType callback, char* substFileName, bool cacheIfPossible)
Bobty 6:46285c519af2 264 {
Bobty 6:46285c519af2 265 _commands.push_back(new RdWebServerCmdDef(pCmdStr, cmdType, callback, substFileName, cacheIfPossible));
Bobty 6:46285c519af2 266 }
Bobty 6:46285c519af2 267
Bobty 18:5de680c4cfcb 268 // Form a header to respond
Bobty 17:080f2bed8b36 269 void RdWebServer::formHTTPHeader(const char* rsltCode, const char* contentType, int contentLen)
Bobty 17:080f2bed8b36 270 {
Bobty 23:0fc3d7b5e596 271 const char* closeConnStr = "\r\nConnection: keep-alive";
Bobty 17:080f2bed8b36 272 if(contentLen != -1)
Bobty 22:598a21373539 273 sprintf(_httpHeader, "HTTP/1.1 %s\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: %s\r\nContent-Length: %d%s\r\n\r\n", rsltCode, contentType, contentLen, _closeConnAfterSend ? closeConnStr : "");
Bobty 17:080f2bed8b36 274 else
Bobty 22:598a21373539 275 sprintf(_httpHeader, "HTTP/1.1 %s\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: %s%s\r\n\r\n", rsltCode, contentType, _closeConnAfterSend ? closeConnStr : "");
Bobty 17:080f2bed8b36 276 }
Bobty 18:5de680c4cfcb 277
Bobty 18:5de680c4cfcb 278 // Use file extension to determine MIME type
Bobty 17:080f2bed8b36 279 char* getMimeTypeStr(char* filename)
Bobty 6:46285c519af2 280 {
Bobty 17:080f2bed8b36 281 char* mimeType = "text/plain";
Bobty 17:080f2bed8b36 282 char *pDot = strrchr(filename, '.');
Bobty 17:080f2bed8b36 283 if (pDot && (!strcmp(pDot, ".html") || !strcmp(pDot, ".htm")))
Bobty 17:080f2bed8b36 284 mimeType = "text/html";
Bobty 17:080f2bed8b36 285 else if (pDot && !strcmp(pDot, ".css"))
Bobty 17:080f2bed8b36 286 mimeType = "text/css";
Bobty 17:080f2bed8b36 287 else if (pDot && !strcmp(pDot, ".js"))
Bobty 17:080f2bed8b36 288 mimeType = "application/javascript";
Bobty 17:080f2bed8b36 289 else if (pDot && !strcmp(pDot, ".png"))
Bobty 17:080f2bed8b36 290 mimeType = "image/png";
Bobty 17:080f2bed8b36 291 else if (pDot && (!strcmp(pDot, ".jpeg") || !strcmp(pDot, ".jpeg")))
Bobty 17:080f2bed8b36 292 mimeType = "image/jpeg";
Bobty 17:080f2bed8b36 293 return mimeType;
Bobty 17:080f2bed8b36 294 }
Bobty 18:5de680c4cfcb 295
Bobty 18:5de680c4cfcb 296 // Handle request for files/listing from SDCard
Bobty 17:080f2bed8b36 297 bool RdWebServer::handleSDFileRequest(char* inFileName, char* argStr, TCPSocketConnection &clientSocketConn)
Bobty 17:080f2bed8b36 298 {
Bobty 17:080f2bed8b36 299 bool handledOk = false;
Bobty 6:46285c519af2 300 const int HTTPD_MAX_FNAME_LENGTH = 127;
Bobty 6:46285c519af2 301 char filename[HTTPD_MAX_FNAME_LENGTH+1];
Bobty 6:46285c519af2 302
Bobty 19:f67ac231b570 303 RD_INFO("Requesting file %s", inFileName);
Bobty 6:46285c519af2 304
Bobty 12:c14ffd4ec125 305 #ifdef SUPPORT_FOLDER_VIEW
Bobty 10:b4b9d4d5e5be 306 if ((strlen(inFileName) > 0) && (inFileName[strlen(inFileName)-1] == '/'))
Bobty 6:46285c519af2 307 {
Bobty 19:f67ac231b570 308 RD_INFO("Request directory %s%s", _pBaseWebFolder, inFileName);
Bobty 6:46285c519af2 309 sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
Bobty 6:46285c519af2 310 DIR *d = opendir(filename);
Bobty 11:cec51b430b20 311 if (d != NULL)
Bobty 11:cec51b430b20 312 {
Bobty 17:080f2bed8b36 313 formHTTPHeader("200 OK", "text/html", -1);
Bobty 23:0fc3d7b5e596 314 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 315 sprintf(_httpHeader,"<html><head><title>Directory Listing</title></head><body><h1>%s</h1><ul>", inFileName);
Bobty 23:0fc3d7b5e596 316 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 317 struct dirent *p;
Bobty 11:cec51b430b20 318 while((p = readdir(d)) != NULL)
Bobty 11:cec51b430b20 319 {
Bobty 19:f67ac231b570 320 RD_INFO("%s", p->d_name);
Bobty 17:080f2bed8b36 321 sprintf(_httpHeader,"<li>%s</li>", p->d_name);
Bobty 23:0fc3d7b5e596 322 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 323 }
Bobty 6:46285c519af2 324 }
Bobty 6:46285c519af2 325 closedir(d);
Bobty 11:cec51b430b20 326 RD_DBG("Directory closed\n");
Bobty 17:080f2bed8b36 327 sprintf(_httpHeader,"</ul></body></html>");
Bobty 23:0fc3d7b5e596 328 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 329 handledOk = true;
Bobty 6:46285c519af2 330 }
Bobty 6:46285c519af2 331 else
Bobty 12:c14ffd4ec125 332 #endif
Bobty 6:46285c519af2 333 {
Bobty 6:46285c519af2 334 sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
Bobty 19:f67ac231b570 335 RD_INFO("Filename %s", filename);
Bobty 6:46285c519af2 336
Bobty 6:46285c519af2 337 FILE* fp = fopen(filename, "r");
Bobty 6:46285c519af2 338 if (fp == NULL)
Bobty 6:46285c519af2 339 {
Bobty 19:f67ac231b570 340 RD_WARN("Filename %s not found", filename);
Bobty 17:080f2bed8b36 341 formHTTPHeader("404 Not Found", "text/plain", 0);
Bobty 23:0fc3d7b5e596 342 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 343 handledOk = true;
Bobty 6:46285c519af2 344 }
Bobty 6:46285c519af2 345 else
Bobty 6:46285c519af2 346 {
Bobty 19:f67ac231b570 347 RD_INFO("Sending file %s", filename);
Bobty 17:080f2bed8b36 348 // Find file length
Bobty 14:4b83670854f0 349 fseek(fp, 0L, SEEK_END);
Bobty 14:4b83670854f0 350 int sz = ftell(fp);
Bobty 14:4b83670854f0 351 fseek(fp, 0L, SEEK_SET);
Bobty 17:080f2bed8b36 352 // Get mime type
Bobty 17:080f2bed8b36 353 char* mimeType = getMimeTypeStr(filename);
Bobty 18:5de680c4cfcb 354 RD_DBG("MIME TYPE %s", mimeType);
Bobty 17:080f2bed8b36 355 // Form header
Bobty 17:080f2bed8b36 356 formHTTPHeader("200 OK", mimeType, sz);
Bobty 23:0fc3d7b5e596 357 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 14:4b83670854f0 358 // Read file in blocks and send
Bobty 6:46285c519af2 359 int rdCnt = 0;
Bobty 6:46285c519af2 360 char fileBuf[1024];
Bobty 6:46285c519af2 361 while ((rdCnt = fread(fileBuf, sizeof( char ), 1024, fp)) == 1024)
Bobty 6:46285c519af2 362 {
Bobty 23:0fc3d7b5e596 363 clientSocketConn.send_all(fileBuf, rdCnt);
Bobty 6:46285c519af2 364 }
Bobty 23:0fc3d7b5e596 365 clientSocketConn.send_all(fileBuf, rdCnt);
Bobty 6:46285c519af2 366 fclose(fp);
Bobty 17:080f2bed8b36 367 handledOk = true;
Bobty 6:46285c519af2 368 }
Bobty 6:46285c519af2 369 }
Bobty 17:080f2bed8b36 370 return handledOk;
Bobty 6:46285c519af2 371 }
Bobty 6:46285c519af2 372
Bobty 18:5de680c4cfcb 373 // Send a file from cache - used for local files only
Bobty 15:0865fa4b046a 374 #ifdef SUPPORT_LOCAL_FILE_CACHE
Bobty 17:080f2bed8b36 375 void RdWebServer::sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection &clientSocketConn)
Bobty 6:46285c519af2 376 {
Bobty 19:f67ac231b570 377 RD_INFO("Sending file %s from cache %d bytes", pCacheEntry->_fileName, pCacheEntry->_nFileLen);
Bobty 17:080f2bed8b36 378 // Get mime type
Bobty 17:080f2bed8b36 379 char* mimeType = getMimeTypeStr(pCacheEntry->_fileName);
Bobty 17:080f2bed8b36 380 RD_INFO("MIME TYPE %s", mimeType);
Bobty 17:080f2bed8b36 381 // Form header
Bobty 17:080f2bed8b36 382 formHTTPHeader("200 OK", mimeType, pCacheEntry->_nFileLen);
Bobty 23:0fc3d7b5e596 383 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 384 char* pMem = pCacheEntry->_pFileContent;
Bobty 6:46285c519af2 385 int nLenLeft = pCacheEntry->_nFileLen;
Bobty 6:46285c519af2 386 int blkSize = 2048;
Bobty 6:46285c519af2 387 while(nLenLeft > 0)
Bobty 6:46285c519af2 388 {
Bobty 6:46285c519af2 389 if (blkSize > nLenLeft)
Bobty 6:46285c519af2 390 blkSize = nLenLeft;
Bobty 23:0fc3d7b5e596 391 clientSocketConn.send_all(pMem, blkSize);
Bobty 6:46285c519af2 392 pMem += blkSize;
Bobty 6:46285c519af2 393 nLenLeft -= blkSize;
Bobty 6:46285c519af2 394 }
Bobty 6:46285c519af2 395 }
Bobty 15:0865fa4b046a 396 #endif
Bobty 6:46285c519af2 397
Bobty 18:5de680c4cfcb 398 // Handle a request for a local file
Bobty 17:080f2bed8b36 399 bool RdWebServer::handleLocalFileRequest(char* inFileName, char* argStr, TCPSocketConnection &clientSocketConn, bool bCacheIfPossible)
Bobty 6:46285c519af2 400 {
Bobty 12:c14ffd4ec125 401
Bobty 12:c14ffd4ec125 402 #ifdef SUPPORT_LOCAL_FILESYSTEM
Bobty 12:c14ffd4ec125 403
Bobty 6:46285c519af2 404 const int HTTPD_MAX_FNAME_LENGTH = 127;
Bobty 6:46285c519af2 405 char localFilename[HTTPD_MAX_FNAME_LENGTH+1];
Bobty 6:46285c519af2 406 char reqFileNameStr[HTTPD_MAX_FNAME_LENGTH+1];
Bobty 6:46285c519af2 407
Bobty 19:f67ac231b570 408 RD_INFO("Requesting local file %s", inFileName);
Bobty 6:46285c519af2 409 sprintf(reqFileNameStr, "/%s", inFileName);
Bobty 6:46285c519af2 410 sprintf(localFilename, "/local/%s", inFileName);
Bobty 6:46285c519af2 411
Bobty 6:46285c519af2 412 if (bCacheIfPossible)
Bobty 6:46285c519af2 413 {
Bobty 6:46285c519af2 414 // Check if file already cached
Bobty 6:46285c519af2 415 bool bTryToCache = true;
Bobty 6:46285c519af2 416 for (std::vector<RdFileCacheEntry*>::iterator it = _cachedFiles.begin() ; it != _cachedFiles.end(); ++it)
Bobty 6:46285c519af2 417 {
Bobty 6:46285c519af2 418 if (strcmp(inFileName, (*it)->_fileName) == 0)
Bobty 6:46285c519af2 419 {
Bobty 6:46285c519af2 420 if ((*it)->_bCacheValid)
Bobty 6:46285c519af2 421 {
Bobty 21:2dfb56648b93 422 sendFromCache(*it, clientSocketConn);
Bobty 17:080f2bed8b36 423 return true;
Bobty 6:46285c519af2 424 }
Bobty 6:46285c519af2 425 bTryToCache = false; // don't try to cache as cacheing must have already failed
Bobty 6:46285c519af2 426 }
Bobty 6:46285c519af2 427 }
Bobty 6:46285c519af2 428
Bobty 6:46285c519af2 429 // See if we can cache the file
Bobty 6:46285c519af2 430 if (bTryToCache)
Bobty 6:46285c519af2 431 {
Bobty 6:46285c519af2 432 RdFileCacheEntry* pCacheEntry = new RdFileCacheEntry(inFileName);
Bobty 6:46285c519af2 433 if (pCacheEntry)
Bobty 6:46285c519af2 434 {
Bobty 6:46285c519af2 435 bool bCacheSuccess = pCacheEntry->readLocalFileIntoCache(localFilename);
Bobty 6:46285c519af2 436 // Store the cache entry even if reading failed (mem alloc or file not found, etc) so we don't try to cache again
Bobty 6:46285c519af2 437 _cachedFiles.push_back(pCacheEntry);
Bobty 6:46285c519af2 438 if (bCacheSuccess)
Bobty 6:46285c519af2 439 {
Bobty 21:2dfb56648b93 440 sendFromCache(pCacheEntry, clientSocketConn);
Bobty 17:080f2bed8b36 441 return true;
Bobty 6:46285c519af2 442 }
Bobty 6:46285c519af2 443 }
Bobty 6:46285c519af2 444 }
Bobty 6:46285c519af2 445 }
Bobty 6:46285c519af2 446
Bobty 6:46285c519af2 447 LocalFileSystem local("local");
Bobty 6:46285c519af2 448
Bobty 6:46285c519af2 449 FILE* fp = fopen(localFilename, "r");
Bobty 6:46285c519af2 450 if (fp == NULL)
Bobty 6:46285c519af2 451 {
Bobty 19:f67ac231b570 452 RD_WARN("Local file %s not found", localFilename);
Bobty 17:080f2bed8b36 453 formHTTPHeader("404 Not Found", "text/plain", 0);
Bobty 23:0fc3d7b5e596 454 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 455 return true;
Bobty 6:46285c519af2 456 }
Bobty 6:46285c519af2 457 else
Bobty 6:46285c519af2 458 {
Bobty 19:f67ac231b570 459 RD_INFO("Sending file %s from disk", localFilename);
Bobty 17:080f2bed8b36 460 // Find file length
Bobty 17:080f2bed8b36 461 fseek(fp, 0L, SEEK_END);
Bobty 17:080f2bed8b36 462 int sz = ftell(fp);
Bobty 17:080f2bed8b36 463 fseek(fp, 0L, SEEK_SET);
Bobty 17:080f2bed8b36 464 // Get mime type
Bobty 17:080f2bed8b36 465 char* mimeType = getMimeTypeStr(localFilename);
Bobty 18:5de680c4cfcb 466 RD_DBG("MIME TYPE %s", mimeType);
Bobty 17:080f2bed8b36 467 // Form header
Bobty 17:080f2bed8b36 468 formHTTPHeader("200 OK", mimeType, sz);
Bobty 23:0fc3d7b5e596 469 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 470 int rdCnt = 0;
Bobty 17:080f2bed8b36 471 while ((rdCnt = fread(_httpHeader, sizeof( char ), sizeof(_httpHeader), fp)) == sizeof(_httpHeader))
Bobty 6:46285c519af2 472 {
Bobty 23:0fc3d7b5e596 473 clientSocketConn.send_all(_httpHeader, rdCnt);
Bobty 6:46285c519af2 474 }
Bobty 17:080f2bed8b36 475 if (rdCnt != 0)
Bobty 23:0fc3d7b5e596 476 clientSocketConn.send_all(_httpHeader, rdCnt);
Bobty 6:46285c519af2 477 fclose(fp);
Bobty 17:080f2bed8b36 478 return true;
Bobty 6:46285c519af2 479 }
Bobty 12:c14ffd4ec125 480
Bobty 12:c14ffd4ec125 481 #else
Bobty 12:c14ffd4ec125 482
Bobty 19:f67ac231b570 483 RD_WARN("Local file system not supported");
Bobty 17:080f2bed8b36 484 formHTTPHeader("404 Not Found", "text/plain", 0);
Bobty 23:0fc3d7b5e596 485 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 486 return true;
Bobty 12:c14ffd4ec125 487
Bobty 12:c14ffd4ec125 488 #endif
Bobty 6:46285c519af2 489 }
Bobty 6:46285c519af2 490
Bobty 18:5de680c4cfcb 491 // Read file into cache
Bobty 15:0865fa4b046a 492 #ifdef SUPPORT_LOCAL_FILE_CACHE
Bobty 6:46285c519af2 493 bool RdFileCacheEntry::readLocalFileIntoCache(char* fileName)
Bobty 6:46285c519af2 494 {
Bobty 12:c14ffd4ec125 495 #ifdef SUPPORT_LOCAL_FILESYSTEM
Bobty 12:c14ffd4ec125 496
Bobty 19:f67ac231b570 497 RD_INFO("Reading into cache %s", fileName);
Bobty 6:46285c519af2 498 LocalFileSystem local("local");
Bobty 6:46285c519af2 499 FILE* fp = fopen(fileName, "r");
Bobty 6:46285c519af2 500 if (fp == NULL)
Bobty 6:46285c519af2 501 {
Bobty 19:f67ac231b570 502 RD_WARN("Failed to open file");
Bobty 6:46285c519af2 503 return false;
Bobty 6:46285c519af2 504 }
Bobty 21:2dfb56648b93 505 RD_DBG("Seeking ");
Bobty 6:46285c519af2 506 fseek(fp, 0, SEEK_END);
Bobty 6:46285c519af2 507 _nFileLen = (int)ftell(fp);
Bobty 21:2dfb56648b93 508 RD_DBG("Len %d ", _nFileLen);
Bobty 6:46285c519af2 509 _pFileContent = new char[_nFileLen];
Bobty 21:2dfb56648b93 510 RD_DBG("Buf %08x ", _pFileContent);
Bobty 6:46285c519af2 511 if (!_pFileContent)
Bobty 6:46285c519af2 512 {
Bobty 19:f67ac231b570 513 RD_WARN("Failed to allocate %lu", _nFileLen);
Bobty 6:46285c519af2 514 fclose(fp);
Bobty 6:46285c519af2 515 return false;
Bobty 6:46285c519af2 516 }
Bobty 19:f67ac231b570 517 RD_DBG("Allocated");
Bobty 6:46285c519af2 518 memset(_pFileContent, 0, _nFileLen);
Bobty 6:46285c519af2 519 fseek(fp, 0, SEEK_SET);
Bobty 6:46285c519af2 520 char* pMem = _pFileContent;
Bobty 6:46285c519af2 521 char fileBuf[100];
Bobty 6:46285c519af2 522 int totCnt = 0;
Bobty 6:46285c519af2 523 int rdCnt = 0;
Bobty 19:f67ac231b570 524 RD_DBG("Reading");
Bobty 6:46285c519af2 525 while (true)
Bobty 6:46285c519af2 526 {
Bobty 6:46285c519af2 527 int toRead = _nFileLen - totCnt;
Bobty 6:46285c519af2 528 if (toRead > sizeof(fileBuf))
Bobty 6:46285c519af2 529 toRead = sizeof(fileBuf);
Bobty 6:46285c519af2 530 if (toRead <= 0)
Bobty 6:46285c519af2 531 break;
Bobty 6:46285c519af2 532 rdCnt = fread(fileBuf, sizeof(char), toRead, fp);
Bobty 6:46285c519af2 533 if (rdCnt <= 0)
Bobty 6:46285c519af2 534 break;
Bobty 19:f67ac231b570 535 RD_DBG("Read %d tot %d of %d", rdCnt, totCnt, _nFileLen);
Bobty 6:46285c519af2 536 memcpy(pMem, fileBuf, rdCnt);
Bobty 6:46285c519af2 537 pMem += rdCnt;
Bobty 6:46285c519af2 538 totCnt += rdCnt;
Bobty 6:46285c519af2 539 }
Bobty 19:f67ac231b570 540 RD_DBG("Done read");
Bobty 6:46285c519af2 541 fclose(fp);
Bobty 19:f67ac231b570 542 RD_DBG("Success in caching %d bytes (read %d)", _nFileLen, totCnt);
Bobty 6:46285c519af2 543 _bCacheValid = true;
Bobty 0:b5b4d07f7827 544 return true;
Bobty 12:c14ffd4ec125 545 #else
Bobty 12:c14ffd4ec125 546 return false;
Bobty 12:c14ffd4ec125 547 #endif
Bobty 0:b5b4d07f7827 548 }
Bobty 0:b5b4d07f7827 549
Bobty 15:0865fa4b046a 550 #endif
Bobty 15:0865fa4b046a 551
Bobty 18:5de680c4cfcb 552 // Extract arguments from command
Bobty 24:27800de38eab 553 bool RdWebServer::extractCmdArgs(char* buf, char* pCmdStr, int maxCmdStrLen, char* pArgStr, int maxArgStrLen, int& contentLen)
Bobty 1:75bb184de749 554 {
Bobty 24:27800de38eab 555 contentLen = -1;
Bobty 1:75bb184de749 556 *pCmdStr = '\0';
Bobty 1:75bb184de749 557 *pArgStr = '\0';
Bobty 1:75bb184de749 558 int cmdStrLen = 0;
Bobty 1:75bb184de749 559 int argStrLen = 0;
Bobty 1:75bb184de749 560 if (buf == NULL)
Bobty 1:75bb184de749 561 return false;
Bobty 24:27800de38eab 562 // Check for Content-length header
Bobty 24:27800de38eab 563 char* contentLenText = "Content-Length:";
Bobty 24:27800de38eab 564 char* pContLen = strstr(buf, contentLenText);
Bobty 24:27800de38eab 565 if (pContLen)
Bobty 24:27800de38eab 566 {
Bobty 24:27800de38eab 567 if (*(pContLen + strlen(contentLenText)) != '\0')
Bobty 24:27800de38eab 568 contentLen = atoi(pContLen + strlen(contentLenText));
Bobty 24:27800de38eab 569 }
Bobty 24:27800de38eab 570
Bobty 7:fe7c33f7fbb8 571 // Check for first slash
Bobty 1:75bb184de749 572 char* pSlash1 = strchr(buf, '/');
Bobty 1:75bb184de749 573 if (pSlash1 == NULL)
Bobty 1:75bb184de749 574 return false;
Bobty 1:75bb184de749 575 pSlash1++;
Bobty 7:fe7c33f7fbb8 576 // Extract command
Bobty 1:75bb184de749 577 while(*pSlash1)
Bobty 1:75bb184de749 578 {
Bobty 1:75bb184de749 579 if (cmdStrLen >= maxCmdStrLen-1)
Bobty 1:75bb184de749 580 break;
Bobty 7:fe7c33f7fbb8 581 if ((*pSlash1 == '/') || (*pSlash1 == ' ') || (*pSlash1 == '\n') || (*pSlash1 == '?') || (*pSlash1 == '&'))
Bobty 1:75bb184de749 582 break;
Bobty 1:75bb184de749 583 *pCmdStr++ = *pSlash1++;
Bobty 1:75bb184de749 584 *pCmdStr = '\0';
Bobty 1:75bb184de749 585 cmdStrLen++;
Bobty 1:75bb184de749 586 }
Bobty 1:75bb184de749 587 if ((*pSlash1 == '\0') || (*pSlash1 == ' ') || (*pSlash1 == '\n'))
Bobty 1:75bb184de749 588 return true;
Bobty 7:fe7c33f7fbb8 589 // Now args
Bobty 1:75bb184de749 590 *pSlash1++;
Bobty 1:75bb184de749 591 while(*pSlash1)
Bobty 1:75bb184de749 592 {
Bobty 1:75bb184de749 593 if (argStrLen >= maxArgStrLen-1)
Bobty 1:75bb184de749 594 break;
Bobty 1:75bb184de749 595 if ((*pSlash1 == ' ') || (*pSlash1 == '\n'))
Bobty 1:75bb184de749 596 break;
Bobty 1:75bb184de749 597 *pArgStr++ = *pSlash1++;
Bobty 1:75bb184de749 598 *pArgStr = '\0';
Bobty 1:75bb184de749 599 argStrLen++;
Bobty 1:75bb184de749 600 }
Bobty 1:75bb184de749 601 return true;
Bobty 1:75bb184de749 602 }
Bobty 19:f67ac231b570 603
Bobty 24:27800de38eab 604 unsigned char* RdWebServer::getPayloadDataFromMsg(char* msgBuf, int msgLen, int& payloadLen)
Bobty 19:f67ac231b570 605 {
Bobty 24:27800de38eab 606 payloadLen = -1;
Bobty 19:f67ac231b570 607 char* ptr = strstr(msgBuf, "\r\n\r\n");
Bobty 19:f67ac231b570 608 if (ptr)
Bobty 24:27800de38eab 609 {
Bobty 24:27800de38eab 610 payloadLen = msgLen - (ptr+4-msgBuf);
Bobty 21:2dfb56648b93 611 return (unsigned char*) (ptr+4);
Bobty 24:27800de38eab 612 }
Bobty 24:27800de38eab 613 return NULL;
Bobty 19:f67ac231b570 614 }
Bobty 21:2dfb56648b93 615
Bobty 24:27800de38eab 616 int RdWebServer::getContentLengthFromMsg(char* msgBuf)
Bobty 21:2dfb56648b93 617 {
Bobty 21:2dfb56648b93 618 char* ptr = strstr(msgBuf, "Content-Length:");
Bobty 21:2dfb56648b93 619 if (ptr)
Bobty 21:2dfb56648b93 620 {
Bobty 21:2dfb56648b93 621 ptr += 15;
Bobty 21:2dfb56648b93 622 int contentLen = atoi(ptr);
Bobty 21:2dfb56648b93 623 if (contentLen >= 0)
Bobty 21:2dfb56648b93 624 return contentLen;
Bobty 21:2dfb56648b93 625 }
Bobty 21:2dfb56648b93 626 return 0;
Bobty 21:2dfb56648b93 627 }