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 Aug 31 15:00:41 2015 +0000
Revision:
24:27800de38eab
Parent:
23:0fc3d7b5e596
Child:
25:ffa1dddd3da4
Implemented handling of split-payloads in HTTP requests. This is done by sending a registered command each chunk of payload data as it arrives with an index indicating where the data fits in the original message.

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 19:f67ac231b570 118 RD_DBG("clientSocketConn.receive() returned %d", rxLen);
Bobty 17:080f2bed8b36 119 if (_closeConnOnReceiveFail)
Bobty 15:0865fa4b046a 120 {
Bobty 15:0865fa4b046a 121 int closeRet = clientSocketConn.close();
Bobty 19:f67ac231b570 122 RD_DBG("Failed receive connection close() ret %d is connected %d", closeRet, clientSocketConn.is_connected());
Bobty 15:0865fa4b046a 123 forcedClosed = true;
Bobty 15:0865fa4b046a 124 }
Bobty 15:0865fa4b046a 125 continue;
Bobty 15:0865fa4b046a 126 }
Bobty 15:0865fa4b046a 127 if (rxLen == 0)
Bobty 15:0865fa4b046a 128 {
Bobty 19:f67ac231b570 129 RD_DBG("clientSocketConn.receive() returned %d - ignoring - is connected %d", rxLen, clientSocketConn.is_connected());
Bobty 15:0865fa4b046a 130 continue;
Bobty 15:0865fa4b046a 131 }
Bobty 18:5de680c4cfcb 132
Bobty 18:5de680c4cfcb 133 // Handle received message
Bobty 15:0865fa4b046a 134 _buffer[rxLen] = '\0';
Bobty 24:27800de38eab 135 _bufferReceivedLen = rxLen;
Bobty 24:27800de38eab 136 handleReceivedHttp(clientSocketConn);
Bobty 15:0865fa4b046a 137
Bobty 17:080f2bed8b36 138 // Close connection if required
Bobty 17:080f2bed8b36 139 if (_closeConnAfterSend)
Bobty 15:0865fa4b046a 140 {
Bobty 15:0865fa4b046a 141 int closeRet = clientSocketConn.close();
Bobty 19:f67ac231b570 142 RD_DBG("After send connection close() ret %d is connected %d", closeRet, clientSocketConn.is_connected());
Bobty 16:0248bbfdb6c1 143 forcedClosed = true;
Bobty 15:0865fa4b046a 144 }
Bobty 15:0865fa4b046a 145 }
Bobty 15:0865fa4b046a 146 }
Bobty 15:0865fa4b046a 147 }
Bobty 18:5de680c4cfcb 148
Bobty 18:5de680c4cfcb 149 // Handle a request
Bobty 15:0865fa4b046a 150 bool RdWebServer::handleReceivedHttp(TCPSocketConnection &clientSocketConn)
Bobty 6:46285c519af2 151 {
Bobty 17:080f2bed8b36 152 bool handledOk = false;
Bobty 24:27800de38eab 153
Bobty 24:27800de38eab 154 // Check for split payload
Bobty 24:27800de38eab 155 if (_curSplitPayloadPos != -1)
Bobty 24:27800de38eab 156 {
Bobty 24:27800de38eab 157 // Handle remaining parts of content
Bobty 24:27800de38eab 158 char* respStr = (_curWebServerCmdDef->_callback)(_curHttpMethod, _curCmdStr, _curArgStr, _buffer, _bufferReceivedLen,
Bobty 24:27800de38eab 159 _curContentLen, (unsigned char*)_buffer, _bufferReceivedLen, _curSplitPayloadPos);
Bobty 24:27800de38eab 160 RD_DBG("Received part of message - content %d - rx %d - splitAfter %d", _curContentLen, _bufferReceivedLen, _curSplitPayloadPos);
Bobty 24:27800de38eab 161 _curSplitPayloadPos += _bufferReceivedLen;
Bobty 24:27800de38eab 162 // Check if all received
Bobty 24:27800de38eab 163 if (_curSplitPayloadPos >= _curContentLen)
Bobty 24:27800de38eab 164 {
Bobty 24:27800de38eab 165 _curSplitPayloadPos = -1;
Bobty 24:27800de38eab 166 clientSocketConn.send_all(respStr, strlen(respStr));
Bobty 24:27800de38eab 167 RD_DBG("That was the end of message - content %d - rx %d", _curContentLen, _bufferReceivedLen);
Bobty 24:27800de38eab 168 }
Bobty 24:27800de38eab 169 return true;
Bobty 24:27800de38eab 170 }
Bobty 24:27800de38eab 171
Bobty 24:27800de38eab 172 // Get payload information
Bobty 24:27800de38eab 173 int payloadLen = -1;
Bobty 24:27800de38eab 174 unsigned char* pPayload = getPayloadDataFromMsg(_buffer, _bufferReceivedLen, payloadLen);
Bobty 24:27800de38eab 175
Bobty 24:27800de38eab 176 // Debug
Bobty 24:27800de38eab 177 int displayLen = _bufferReceivedLen;
Bobty 24:27800de38eab 178 if (payloadLen > 0)
Bobty 24:27800de38eab 179 displayLen = _bufferReceivedLen-payloadLen;
Bobty 24:27800de38eab 180 RD_DBG("\r\nNEW REQUEST RxLen %d ContentLen %d PayloadLen %d\n\r\n\r%.*s", _bufferReceivedLen, _curContentLen, payloadLen, displayLen, _buffer);
Bobty 24:27800de38eab 181
Bobty 24:27800de38eab 182 // Get HTTP method
Bobty 24:27800de38eab 183 _curHttpMethod = METHOD_OTHER;
Bobty 6:46285c519af2 184 if (strncmp(_buffer, "GET ", 4) == 0)
Bobty 24:27800de38eab 185 _curHttpMethod = METHOD_GET;
Bobty 23:0fc3d7b5e596 186 else if (strncmp(_buffer, "POST", 4) == 0)
Bobty 24:27800de38eab 187 _curHttpMethod = METHOD_POST;
Bobty 23:0fc3d7b5e596 188 else if (strncmp(_buffer, "OPTIONS", 7) == 0)
Bobty 24:27800de38eab 189 _curHttpMethod = METHOD_OPTIONS;
Bobty 7:fe7c33f7fbb8 190
Bobty 24:27800de38eab 191 // See if there is a valid HTTP command
Bobty 24:27800de38eab 192 _curContentLen = -1;
Bobty 24:27800de38eab 193 if (extractCmdArgs(_buffer+3, _curCmdStr, MAX_CMDSTR_LEN, _curArgStr, MAX_ARGSTR_LEN, _curContentLen))
Bobty 6:46285c519af2 194 {
Bobty 24:27800de38eab 195 RD_DBG("CmdStr %s", _curCmdStr);
Bobty 24:27800de38eab 196 RD_DBG("ArgStr %s", _curArgStr);
Bobty 24:27800de38eab 197
Bobty 7:fe7c33f7fbb8 198 bool cmdFound = false;
Bobty 7:fe7c33f7fbb8 199 for (std::vector<RdWebServerCmdDef*>::iterator it = _commands.begin() ; it != _commands.end(); ++it)
Bobty 6:46285c519af2 200 {
Bobty 24:27800de38eab 201 if (strcasecmp((*it)->_pCmdStr, _curCmdStr) == 0)
Bobty 24:27800de38eab 202 {
Bobty 24:27800de38eab 203 RD_DBG("FoundCmd <%s> Type %d", _curCmdStr, (*it)->_cmdType);
Bobty 7:fe7c33f7fbb8 204 cmdFound = true;
Bobty 7:fe7c33f7fbb8 205 if ((*it)->_cmdType == RdWebServerCmdDef::CMD_CALLBACK)
Bobty 7:fe7c33f7fbb8 206 {
Bobty 24:27800de38eab 207 char* respStr = ((*it)->_callback)(_curHttpMethod, _curCmdStr, _curArgStr, _buffer, _bufferReceivedLen,
Bobty 24:27800de38eab 208 _curContentLen, pPayload, payloadLen, 0);
Bobty 24:27800de38eab 209 // Handle split-payload situation
Bobty 24:27800de38eab 210 if (_curContentLen > 0 && payloadLen < _curContentLen)
Bobty 24:27800de38eab 211 {
Bobty 24:27800de38eab 212 _curSplitPayloadPos = payloadLen;
Bobty 24:27800de38eab 213 _curWebServerCmdDef = (*it);
Bobty 24:27800de38eab 214 }
Bobty 24:27800de38eab 215 else
Bobty 24:27800de38eab 216 {
Bobty 24:27800de38eab 217 clientSocketConn.send_all(respStr, strlen(respStr));
Bobty 24:27800de38eab 218 }
Bobty 24:27800de38eab 219 handledOk = true;
Bobty 6:46285c519af2 220 }
Bobty 17:080f2bed8b36 221 else if ( ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE) ||
Bobty 17:080f2bed8b36 222 ((*it)->_cmdType == RdWebServerCmdDef::CMD_SDORUSBFILE) )
Bobty 7:fe7c33f7fbb8 223 {
Bobty 17:080f2bed8b36 224 char combinedFileName[MAX_FILENAME_LEN];
Bobty 17:080f2bed8b36 225 strcpy(combinedFileName, (*it)->_substFileName);
Bobty 17:080f2bed8b36 226 if (strlen(combinedFileName) == 0)
Bobty 24:27800de38eab 227 strcpy(combinedFileName, _curCmdStr);
Bobty 17:080f2bed8b36 228 else if (combinedFileName[strlen(combinedFileName)-1] == '*')
Bobty 24:27800de38eab 229 strcpy(combinedFileName+strlen(combinedFileName)-1, _curArgStr);
Bobty 17:080f2bed8b36 230 if ((*it)->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE)
Bobty 24:27800de38eab 231 handledOk = handleLocalFileRequest(combinedFileName, _curArgStr, clientSocketConn, (*it)->_bCacheIfPossible);
Bobty 7:fe7c33f7fbb8 232 else
Bobty 24:27800de38eab 233 handledOk = handleSDFileRequest(combinedFileName, _curArgStr, clientSocketConn);
Bobty 17:080f2bed8b36 234
Bobty 7:fe7c33f7fbb8 235 }
Bobty 7:fe7c33f7fbb8 236 break;
Bobty 6:46285c519af2 237 }
Bobty 6:46285c519af2 238 }
Bobty 7:fe7c33f7fbb8 239 // If command not found see if it is a local file
Bobty 7:fe7c33f7fbb8 240 if (!cmdFound)
Bobty 17:080f2bed8b36 241 {
Bobty 17:080f2bed8b36 242 char combinedFileName[MAX_FILENAME_LEN];
Bobty 24:27800de38eab 243 strcpy(combinedFileName, _curCmdStr);
Bobty 17:080f2bed8b36 244 strcat(combinedFileName, "/");
Bobty 24:27800de38eab 245 strcat(combinedFileName, _curArgStr);
Bobty 24:27800de38eab 246 handledOk = handleSDFileRequest(combinedFileName, _curArgStr, clientSocketConn);
Bobty 17:080f2bed8b36 247 }
Bobty 6:46285c519af2 248 }
Bobty 24:27800de38eab 249 else
Bobty 24:27800de38eab 250 {
Bobty 24:27800de38eab 251 RD_DBG("Cannot find command or args\r\n");
Bobty 24:27800de38eab 252 }
Bobty 17:080f2bed8b36 253 return handledOk;
Bobty 6:46285c519af2 254 }
Bobty 6:46285c519af2 255
Bobty 18:5de680c4cfcb 256 // Add a command to the server
Bobty 6:46285c519af2 257 void RdWebServer::addCommand(char* pCmdStr, int cmdType, CmdCallbackType callback, char* substFileName, bool cacheIfPossible)
Bobty 6:46285c519af2 258 {
Bobty 6:46285c519af2 259 _commands.push_back(new RdWebServerCmdDef(pCmdStr, cmdType, callback, substFileName, cacheIfPossible));
Bobty 6:46285c519af2 260 }
Bobty 6:46285c519af2 261
Bobty 18:5de680c4cfcb 262 // Form a header to respond
Bobty 17:080f2bed8b36 263 void RdWebServer::formHTTPHeader(const char* rsltCode, const char* contentType, int contentLen)
Bobty 17:080f2bed8b36 264 {
Bobty 23:0fc3d7b5e596 265 const char* closeConnStr = "\r\nConnection: keep-alive";
Bobty 17:080f2bed8b36 266 if(contentLen != -1)
Bobty 22:598a21373539 267 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 268 else
Bobty 22:598a21373539 269 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 270 }
Bobty 18:5de680c4cfcb 271
Bobty 18:5de680c4cfcb 272 // Use file extension to determine MIME type
Bobty 17:080f2bed8b36 273 char* getMimeTypeStr(char* filename)
Bobty 6:46285c519af2 274 {
Bobty 17:080f2bed8b36 275 char* mimeType = "text/plain";
Bobty 17:080f2bed8b36 276 char *pDot = strrchr(filename, '.');
Bobty 17:080f2bed8b36 277 if (pDot && (!strcmp(pDot, ".html") || !strcmp(pDot, ".htm")))
Bobty 17:080f2bed8b36 278 mimeType = "text/html";
Bobty 17:080f2bed8b36 279 else if (pDot && !strcmp(pDot, ".css"))
Bobty 17:080f2bed8b36 280 mimeType = "text/css";
Bobty 17:080f2bed8b36 281 else if (pDot && !strcmp(pDot, ".js"))
Bobty 17:080f2bed8b36 282 mimeType = "application/javascript";
Bobty 17:080f2bed8b36 283 else if (pDot && !strcmp(pDot, ".png"))
Bobty 17:080f2bed8b36 284 mimeType = "image/png";
Bobty 17:080f2bed8b36 285 else if (pDot && (!strcmp(pDot, ".jpeg") || !strcmp(pDot, ".jpeg")))
Bobty 17:080f2bed8b36 286 mimeType = "image/jpeg";
Bobty 17:080f2bed8b36 287 return mimeType;
Bobty 17:080f2bed8b36 288 }
Bobty 18:5de680c4cfcb 289
Bobty 18:5de680c4cfcb 290 // Handle request for files/listing from SDCard
Bobty 17:080f2bed8b36 291 bool RdWebServer::handleSDFileRequest(char* inFileName, char* argStr, TCPSocketConnection &clientSocketConn)
Bobty 17:080f2bed8b36 292 {
Bobty 17:080f2bed8b36 293 bool handledOk = false;
Bobty 6:46285c519af2 294 const int HTTPD_MAX_FNAME_LENGTH = 127;
Bobty 6:46285c519af2 295 char filename[HTTPD_MAX_FNAME_LENGTH+1];
Bobty 6:46285c519af2 296
Bobty 19:f67ac231b570 297 RD_INFO("Requesting file %s", inFileName);
Bobty 6:46285c519af2 298
Bobty 12:c14ffd4ec125 299 #ifdef SUPPORT_FOLDER_VIEW
Bobty 10:b4b9d4d5e5be 300 if ((strlen(inFileName) > 0) && (inFileName[strlen(inFileName)-1] == '/'))
Bobty 6:46285c519af2 301 {
Bobty 19:f67ac231b570 302 RD_INFO("Request directory %s%s", _pBaseWebFolder, inFileName);
Bobty 6:46285c519af2 303 sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
Bobty 6:46285c519af2 304 DIR *d = opendir(filename);
Bobty 11:cec51b430b20 305 if (d != NULL)
Bobty 11:cec51b430b20 306 {
Bobty 17:080f2bed8b36 307 formHTTPHeader("200 OK", "text/html", -1);
Bobty 23:0fc3d7b5e596 308 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 309 sprintf(_httpHeader,"<html><head><title>Directory Listing</title></head><body><h1>%s</h1><ul>", inFileName);
Bobty 23:0fc3d7b5e596 310 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 311 struct dirent *p;
Bobty 11:cec51b430b20 312 while((p = readdir(d)) != NULL)
Bobty 11:cec51b430b20 313 {
Bobty 19:f67ac231b570 314 RD_INFO("%s", p->d_name);
Bobty 17:080f2bed8b36 315 sprintf(_httpHeader,"<li>%s</li>", p->d_name);
Bobty 23:0fc3d7b5e596 316 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 317 }
Bobty 6:46285c519af2 318 }
Bobty 6:46285c519af2 319 closedir(d);
Bobty 11:cec51b430b20 320 RD_DBG("Directory closed\n");
Bobty 17:080f2bed8b36 321 sprintf(_httpHeader,"</ul></body></html>");
Bobty 23:0fc3d7b5e596 322 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 323 handledOk = true;
Bobty 6:46285c519af2 324 }
Bobty 6:46285c519af2 325 else
Bobty 12:c14ffd4ec125 326 #endif
Bobty 6:46285c519af2 327 {
Bobty 6:46285c519af2 328 sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
Bobty 19:f67ac231b570 329 RD_INFO("Filename %s", filename);
Bobty 6:46285c519af2 330
Bobty 6:46285c519af2 331 FILE* fp = fopen(filename, "r");
Bobty 6:46285c519af2 332 if (fp == NULL)
Bobty 6:46285c519af2 333 {
Bobty 19:f67ac231b570 334 RD_WARN("Filename %s not found", filename);
Bobty 17:080f2bed8b36 335 formHTTPHeader("404 Not Found", "text/plain", 0);
Bobty 23:0fc3d7b5e596 336 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 337 handledOk = true;
Bobty 6:46285c519af2 338 }
Bobty 6:46285c519af2 339 else
Bobty 6:46285c519af2 340 {
Bobty 19:f67ac231b570 341 RD_INFO("Sending file %s", filename);
Bobty 17:080f2bed8b36 342 // Find file length
Bobty 14:4b83670854f0 343 fseek(fp, 0L, SEEK_END);
Bobty 14:4b83670854f0 344 int sz = ftell(fp);
Bobty 14:4b83670854f0 345 fseek(fp, 0L, SEEK_SET);
Bobty 17:080f2bed8b36 346 // Get mime type
Bobty 17:080f2bed8b36 347 char* mimeType = getMimeTypeStr(filename);
Bobty 18:5de680c4cfcb 348 RD_DBG("MIME TYPE %s", mimeType);
Bobty 17:080f2bed8b36 349 // Form header
Bobty 17:080f2bed8b36 350 formHTTPHeader("200 OK", mimeType, sz);
Bobty 23:0fc3d7b5e596 351 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 14:4b83670854f0 352 // Read file in blocks and send
Bobty 6:46285c519af2 353 int rdCnt = 0;
Bobty 6:46285c519af2 354 char fileBuf[1024];
Bobty 6:46285c519af2 355 while ((rdCnt = fread(fileBuf, sizeof( char ), 1024, fp)) == 1024)
Bobty 6:46285c519af2 356 {
Bobty 23:0fc3d7b5e596 357 clientSocketConn.send_all(fileBuf, rdCnt);
Bobty 6:46285c519af2 358 }
Bobty 23:0fc3d7b5e596 359 clientSocketConn.send_all(fileBuf, rdCnt);
Bobty 6:46285c519af2 360 fclose(fp);
Bobty 17:080f2bed8b36 361 handledOk = true;
Bobty 6:46285c519af2 362 }
Bobty 6:46285c519af2 363 }
Bobty 17:080f2bed8b36 364 return handledOk;
Bobty 6:46285c519af2 365 }
Bobty 6:46285c519af2 366
Bobty 18:5de680c4cfcb 367 // Send a file from cache - used for local files only
Bobty 15:0865fa4b046a 368 #ifdef SUPPORT_LOCAL_FILE_CACHE
Bobty 17:080f2bed8b36 369 void RdWebServer::sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection &clientSocketConn)
Bobty 6:46285c519af2 370 {
Bobty 19:f67ac231b570 371 RD_INFO("Sending file %s from cache %d bytes", pCacheEntry->_fileName, pCacheEntry->_nFileLen);
Bobty 17:080f2bed8b36 372 // Get mime type
Bobty 17:080f2bed8b36 373 char* mimeType = getMimeTypeStr(pCacheEntry->_fileName);
Bobty 17:080f2bed8b36 374 RD_INFO("MIME TYPE %s", mimeType);
Bobty 17:080f2bed8b36 375 // Form header
Bobty 17:080f2bed8b36 376 formHTTPHeader("200 OK", mimeType, pCacheEntry->_nFileLen);
Bobty 23:0fc3d7b5e596 377 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 378 char* pMem = pCacheEntry->_pFileContent;
Bobty 6:46285c519af2 379 int nLenLeft = pCacheEntry->_nFileLen;
Bobty 6:46285c519af2 380 int blkSize = 2048;
Bobty 6:46285c519af2 381 while(nLenLeft > 0)
Bobty 6:46285c519af2 382 {
Bobty 6:46285c519af2 383 if (blkSize > nLenLeft)
Bobty 6:46285c519af2 384 blkSize = nLenLeft;
Bobty 23:0fc3d7b5e596 385 clientSocketConn.send_all(pMem, blkSize);
Bobty 6:46285c519af2 386 pMem += blkSize;
Bobty 6:46285c519af2 387 nLenLeft -= blkSize;
Bobty 6:46285c519af2 388 }
Bobty 6:46285c519af2 389 }
Bobty 15:0865fa4b046a 390 #endif
Bobty 6:46285c519af2 391
Bobty 18:5de680c4cfcb 392 // Handle a request for a local file
Bobty 17:080f2bed8b36 393 bool RdWebServer::handleLocalFileRequest(char* inFileName, char* argStr, TCPSocketConnection &clientSocketConn, bool bCacheIfPossible)
Bobty 6:46285c519af2 394 {
Bobty 12:c14ffd4ec125 395
Bobty 12:c14ffd4ec125 396 #ifdef SUPPORT_LOCAL_FILESYSTEM
Bobty 12:c14ffd4ec125 397
Bobty 6:46285c519af2 398 const int HTTPD_MAX_FNAME_LENGTH = 127;
Bobty 6:46285c519af2 399 char localFilename[HTTPD_MAX_FNAME_LENGTH+1];
Bobty 6:46285c519af2 400 char reqFileNameStr[HTTPD_MAX_FNAME_LENGTH+1];
Bobty 6:46285c519af2 401
Bobty 19:f67ac231b570 402 RD_INFO("Requesting local file %s", inFileName);
Bobty 6:46285c519af2 403 sprintf(reqFileNameStr, "/%s", inFileName);
Bobty 6:46285c519af2 404 sprintf(localFilename, "/local/%s", inFileName);
Bobty 6:46285c519af2 405
Bobty 6:46285c519af2 406 if (bCacheIfPossible)
Bobty 6:46285c519af2 407 {
Bobty 6:46285c519af2 408 // Check if file already cached
Bobty 6:46285c519af2 409 bool bTryToCache = true;
Bobty 6:46285c519af2 410 for (std::vector<RdFileCacheEntry*>::iterator it = _cachedFiles.begin() ; it != _cachedFiles.end(); ++it)
Bobty 6:46285c519af2 411 {
Bobty 6:46285c519af2 412 if (strcmp(inFileName, (*it)->_fileName) == 0)
Bobty 6:46285c519af2 413 {
Bobty 6:46285c519af2 414 if ((*it)->_bCacheValid)
Bobty 6:46285c519af2 415 {
Bobty 21:2dfb56648b93 416 sendFromCache(*it, clientSocketConn);
Bobty 17:080f2bed8b36 417 return true;
Bobty 6:46285c519af2 418 }
Bobty 6:46285c519af2 419 bTryToCache = false; // don't try to cache as cacheing must have already failed
Bobty 6:46285c519af2 420 }
Bobty 6:46285c519af2 421 }
Bobty 6:46285c519af2 422
Bobty 6:46285c519af2 423 // See if we can cache the file
Bobty 6:46285c519af2 424 if (bTryToCache)
Bobty 6:46285c519af2 425 {
Bobty 6:46285c519af2 426 RdFileCacheEntry* pCacheEntry = new RdFileCacheEntry(inFileName);
Bobty 6:46285c519af2 427 if (pCacheEntry)
Bobty 6:46285c519af2 428 {
Bobty 6:46285c519af2 429 bool bCacheSuccess = pCacheEntry->readLocalFileIntoCache(localFilename);
Bobty 6:46285c519af2 430 // 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 431 _cachedFiles.push_back(pCacheEntry);
Bobty 6:46285c519af2 432 if (bCacheSuccess)
Bobty 6:46285c519af2 433 {
Bobty 21:2dfb56648b93 434 sendFromCache(pCacheEntry, clientSocketConn);
Bobty 17:080f2bed8b36 435 return true;
Bobty 6:46285c519af2 436 }
Bobty 6:46285c519af2 437 }
Bobty 6:46285c519af2 438 }
Bobty 6:46285c519af2 439 }
Bobty 6:46285c519af2 440
Bobty 6:46285c519af2 441 LocalFileSystem local("local");
Bobty 6:46285c519af2 442
Bobty 6:46285c519af2 443 FILE* fp = fopen(localFilename, "r");
Bobty 6:46285c519af2 444 if (fp == NULL)
Bobty 6:46285c519af2 445 {
Bobty 19:f67ac231b570 446 RD_WARN("Local file %s not found", localFilename);
Bobty 17:080f2bed8b36 447 formHTTPHeader("404 Not Found", "text/plain", 0);
Bobty 23:0fc3d7b5e596 448 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 449 return true;
Bobty 6:46285c519af2 450 }
Bobty 6:46285c519af2 451 else
Bobty 6:46285c519af2 452 {
Bobty 19:f67ac231b570 453 RD_INFO("Sending file %s from disk", localFilename);
Bobty 17:080f2bed8b36 454 // Find file length
Bobty 17:080f2bed8b36 455 fseek(fp, 0L, SEEK_END);
Bobty 17:080f2bed8b36 456 int sz = ftell(fp);
Bobty 17:080f2bed8b36 457 fseek(fp, 0L, SEEK_SET);
Bobty 17:080f2bed8b36 458 // Get mime type
Bobty 17:080f2bed8b36 459 char* mimeType = getMimeTypeStr(localFilename);
Bobty 18:5de680c4cfcb 460 RD_DBG("MIME TYPE %s", mimeType);
Bobty 17:080f2bed8b36 461 // Form header
Bobty 17:080f2bed8b36 462 formHTTPHeader("200 OK", mimeType, sz);
Bobty 23:0fc3d7b5e596 463 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 6:46285c519af2 464 int rdCnt = 0;
Bobty 17:080f2bed8b36 465 while ((rdCnt = fread(_httpHeader, sizeof( char ), sizeof(_httpHeader), fp)) == sizeof(_httpHeader))
Bobty 6:46285c519af2 466 {
Bobty 23:0fc3d7b5e596 467 clientSocketConn.send_all(_httpHeader, rdCnt);
Bobty 6:46285c519af2 468 }
Bobty 17:080f2bed8b36 469 if (rdCnt != 0)
Bobty 23:0fc3d7b5e596 470 clientSocketConn.send_all(_httpHeader, rdCnt);
Bobty 6:46285c519af2 471 fclose(fp);
Bobty 17:080f2bed8b36 472 return true;
Bobty 6:46285c519af2 473 }
Bobty 12:c14ffd4ec125 474
Bobty 12:c14ffd4ec125 475 #else
Bobty 12:c14ffd4ec125 476
Bobty 19:f67ac231b570 477 RD_WARN("Local file system not supported");
Bobty 17:080f2bed8b36 478 formHTTPHeader("404 Not Found", "text/plain", 0);
Bobty 23:0fc3d7b5e596 479 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
Bobty 17:080f2bed8b36 480 return true;
Bobty 12:c14ffd4ec125 481
Bobty 12:c14ffd4ec125 482 #endif
Bobty 6:46285c519af2 483 }
Bobty 6:46285c519af2 484
Bobty 18:5de680c4cfcb 485 // Read file into cache
Bobty 15:0865fa4b046a 486 #ifdef SUPPORT_LOCAL_FILE_CACHE
Bobty 6:46285c519af2 487 bool RdFileCacheEntry::readLocalFileIntoCache(char* fileName)
Bobty 6:46285c519af2 488 {
Bobty 12:c14ffd4ec125 489 #ifdef SUPPORT_LOCAL_FILESYSTEM
Bobty 12:c14ffd4ec125 490
Bobty 19:f67ac231b570 491 RD_INFO("Reading into cache %s", fileName);
Bobty 6:46285c519af2 492 LocalFileSystem local("local");
Bobty 6:46285c519af2 493 FILE* fp = fopen(fileName, "r");
Bobty 6:46285c519af2 494 if (fp == NULL)
Bobty 6:46285c519af2 495 {
Bobty 19:f67ac231b570 496 RD_WARN("Failed to open file");
Bobty 6:46285c519af2 497 return false;
Bobty 6:46285c519af2 498 }
Bobty 21:2dfb56648b93 499 RD_DBG("Seeking ");
Bobty 6:46285c519af2 500 fseek(fp, 0, SEEK_END);
Bobty 6:46285c519af2 501 _nFileLen = (int)ftell(fp);
Bobty 21:2dfb56648b93 502 RD_DBG("Len %d ", _nFileLen);
Bobty 6:46285c519af2 503 _pFileContent = new char[_nFileLen];
Bobty 21:2dfb56648b93 504 RD_DBG("Buf %08x ", _pFileContent);
Bobty 6:46285c519af2 505 if (!_pFileContent)
Bobty 6:46285c519af2 506 {
Bobty 19:f67ac231b570 507 RD_WARN("Failed to allocate %lu", _nFileLen);
Bobty 6:46285c519af2 508 fclose(fp);
Bobty 6:46285c519af2 509 return false;
Bobty 6:46285c519af2 510 }
Bobty 19:f67ac231b570 511 RD_DBG("Allocated");
Bobty 6:46285c519af2 512 memset(_pFileContent, 0, _nFileLen);
Bobty 6:46285c519af2 513 fseek(fp, 0, SEEK_SET);
Bobty 6:46285c519af2 514 char* pMem = _pFileContent;
Bobty 6:46285c519af2 515 char fileBuf[100];
Bobty 6:46285c519af2 516 int totCnt = 0;
Bobty 6:46285c519af2 517 int rdCnt = 0;
Bobty 19:f67ac231b570 518 RD_DBG("Reading");
Bobty 6:46285c519af2 519 while (true)
Bobty 6:46285c519af2 520 {
Bobty 6:46285c519af2 521 int toRead = _nFileLen - totCnt;
Bobty 6:46285c519af2 522 if (toRead > sizeof(fileBuf))
Bobty 6:46285c519af2 523 toRead = sizeof(fileBuf);
Bobty 6:46285c519af2 524 if (toRead <= 0)
Bobty 6:46285c519af2 525 break;
Bobty 6:46285c519af2 526 rdCnt = fread(fileBuf, sizeof(char), toRead, fp);
Bobty 6:46285c519af2 527 if (rdCnt <= 0)
Bobty 6:46285c519af2 528 break;
Bobty 19:f67ac231b570 529 RD_DBG("Read %d tot %d of %d", rdCnt, totCnt, _nFileLen);
Bobty 6:46285c519af2 530 memcpy(pMem, fileBuf, rdCnt);
Bobty 6:46285c519af2 531 pMem += rdCnt;
Bobty 6:46285c519af2 532 totCnt += rdCnt;
Bobty 6:46285c519af2 533 }
Bobty 19:f67ac231b570 534 RD_DBG("Done read");
Bobty 6:46285c519af2 535 fclose(fp);
Bobty 19:f67ac231b570 536 RD_DBG("Success in caching %d bytes (read %d)", _nFileLen, totCnt);
Bobty 6:46285c519af2 537 _bCacheValid = true;
Bobty 0:b5b4d07f7827 538 return true;
Bobty 12:c14ffd4ec125 539 #else
Bobty 12:c14ffd4ec125 540 return false;
Bobty 12:c14ffd4ec125 541 #endif
Bobty 0:b5b4d07f7827 542 }
Bobty 0:b5b4d07f7827 543
Bobty 15:0865fa4b046a 544 #endif
Bobty 15:0865fa4b046a 545
Bobty 18:5de680c4cfcb 546 // Extract arguments from command
Bobty 24:27800de38eab 547 bool RdWebServer::extractCmdArgs(char* buf, char* pCmdStr, int maxCmdStrLen, char* pArgStr, int maxArgStrLen, int& contentLen)
Bobty 1:75bb184de749 548 {
Bobty 24:27800de38eab 549 contentLen = -1;
Bobty 1:75bb184de749 550 *pCmdStr = '\0';
Bobty 1:75bb184de749 551 *pArgStr = '\0';
Bobty 1:75bb184de749 552 int cmdStrLen = 0;
Bobty 1:75bb184de749 553 int argStrLen = 0;
Bobty 1:75bb184de749 554 if (buf == NULL)
Bobty 1:75bb184de749 555 return false;
Bobty 24:27800de38eab 556 // Check for Content-length header
Bobty 24:27800de38eab 557 char* contentLenText = "Content-Length:";
Bobty 24:27800de38eab 558 char* pContLen = strstr(buf, contentLenText);
Bobty 24:27800de38eab 559 if (pContLen)
Bobty 24:27800de38eab 560 {
Bobty 24:27800de38eab 561 if (*(pContLen + strlen(contentLenText)) != '\0')
Bobty 24:27800de38eab 562 contentLen = atoi(pContLen + strlen(contentLenText));
Bobty 24:27800de38eab 563 }
Bobty 24:27800de38eab 564
Bobty 7:fe7c33f7fbb8 565 // Check for first slash
Bobty 1:75bb184de749 566 char* pSlash1 = strchr(buf, '/');
Bobty 1:75bb184de749 567 if (pSlash1 == NULL)
Bobty 1:75bb184de749 568 return false;
Bobty 1:75bb184de749 569 pSlash1++;
Bobty 7:fe7c33f7fbb8 570 // Extract command
Bobty 1:75bb184de749 571 while(*pSlash1)
Bobty 1:75bb184de749 572 {
Bobty 1:75bb184de749 573 if (cmdStrLen >= maxCmdStrLen-1)
Bobty 1:75bb184de749 574 break;
Bobty 7:fe7c33f7fbb8 575 if ((*pSlash1 == '/') || (*pSlash1 == ' ') || (*pSlash1 == '\n') || (*pSlash1 == '?') || (*pSlash1 == '&'))
Bobty 1:75bb184de749 576 break;
Bobty 1:75bb184de749 577 *pCmdStr++ = *pSlash1++;
Bobty 1:75bb184de749 578 *pCmdStr = '\0';
Bobty 1:75bb184de749 579 cmdStrLen++;
Bobty 1:75bb184de749 580 }
Bobty 1:75bb184de749 581 if ((*pSlash1 == '\0') || (*pSlash1 == ' ') || (*pSlash1 == '\n'))
Bobty 1:75bb184de749 582 return true;
Bobty 7:fe7c33f7fbb8 583 // Now args
Bobty 1:75bb184de749 584 *pSlash1++;
Bobty 1:75bb184de749 585 while(*pSlash1)
Bobty 1:75bb184de749 586 {
Bobty 1:75bb184de749 587 if (argStrLen >= maxArgStrLen-1)
Bobty 1:75bb184de749 588 break;
Bobty 1:75bb184de749 589 if ((*pSlash1 == ' ') || (*pSlash1 == '\n'))
Bobty 1:75bb184de749 590 break;
Bobty 1:75bb184de749 591 *pArgStr++ = *pSlash1++;
Bobty 1:75bb184de749 592 *pArgStr = '\0';
Bobty 1:75bb184de749 593 argStrLen++;
Bobty 1:75bb184de749 594 }
Bobty 1:75bb184de749 595 return true;
Bobty 1:75bb184de749 596 }
Bobty 19:f67ac231b570 597
Bobty 24:27800de38eab 598 unsigned char* RdWebServer::getPayloadDataFromMsg(char* msgBuf, int msgLen, int& payloadLen)
Bobty 19:f67ac231b570 599 {
Bobty 24:27800de38eab 600 payloadLen = -1;
Bobty 19:f67ac231b570 601 char* ptr = strstr(msgBuf, "\r\n\r\n");
Bobty 19:f67ac231b570 602 if (ptr)
Bobty 24:27800de38eab 603 {
Bobty 24:27800de38eab 604 payloadLen = msgLen - (ptr+4-msgBuf);
Bobty 21:2dfb56648b93 605 return (unsigned char*) (ptr+4);
Bobty 24:27800de38eab 606 }
Bobty 24:27800de38eab 607 return NULL;
Bobty 19:f67ac231b570 608 }
Bobty 21:2dfb56648b93 609
Bobty 24:27800de38eab 610 int RdWebServer::getContentLengthFromMsg(char* msgBuf)
Bobty 21:2dfb56648b93 611 {
Bobty 21:2dfb56648b93 612 char* ptr = strstr(msgBuf, "Content-Length:");
Bobty 21:2dfb56648b93 613 if (ptr)
Bobty 21:2dfb56648b93 614 {
Bobty 21:2dfb56648b93 615 ptr += 15;
Bobty 21:2dfb56648b93 616 int contentLen = atoi(ptr);
Bobty 21:2dfb56648b93 617 if (contentLen >= 0)
Bobty 21:2dfb56648b93 618 return contentLen;
Bobty 21:2dfb56648b93 619 }
Bobty 21:2dfb56648b93 620 return 0;
Bobty 21:2dfb56648b93 621 }