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.cpp Source File

RdWebServer.cpp

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 #include "RdWebServerDefs.h"
00008 #include "RdWebServer.h"
00009 
00010 // Limits - note particularly the MAX_FILENAME_LEN
00011 const int MAX_FILENAME_LEN = (MAX_ARGSTR_LEN + 20);
00012 
00013 // Constructor
00014 RdWebServer::RdWebServer(TCPSocketServer& tcpServerSocket, Mutex* pSdCardMutex)
00015     : _serverSocket(tcpServerSocket)
00016 {
00017     _initOk = false;
00018     _pStatusLed = NULL;
00019     _curSplitPayloadPos = -1;
00020     _curCmdStr[0] = 0;
00021     _curArgStr[0] = 0;
00022     _bufferReceivedLen = 0;
00023     _curContentLen = -1;
00024     _curHttpMethod = METHOD_OTHER;
00025     _curWebServerCmdDef = NULL;
00026     _pSdCardMutex = pSdCardMutex;
00027     _numWebServerCmds = 0;
00028     _numWebServerCachedFiles = 0;
00029 }
00030 
00031 // Destructor
00032 RdWebServer::~RdWebServer()
00033 {
00034     // Clean-up - probably never called as we're on a microcontroller!
00035     for (int i = 0; i < _numWebServerCmds; i++)
00036         delete _pWebServerCmds[i];
00037     _numWebServerCmds = 0;
00038 }
00039 
00040 // Init
00041 bool RdWebServer::init(int port, DigitalOut* pStatusLed, char* pBaseWebFolder)
00042 {
00043     // Settings
00044     _port = port;
00045     _pStatusLed = pStatusLed;
00046     _pBaseWebFolder = pBaseWebFolder;
00047 
00048     // Non-blocking by default
00049     _blockingOnAccept = false;
00050     _blockingOnReceive = false;
00051     
00052     // This is the same as the default in the socket.cpp file
00053     _timeoutOnBlocking = 1500;
00054     
00055     // If closeConnAfterSend is set false then the socket connection remains open and only
00056     // one client can access the server until a time-out occurs - this should be ok for most applications
00057     _closeConnAfterSend = false;
00058     _closeConnOnReceiveFail = true;
00059 
00060     if(_serverSocket.bind(port)< 0) 
00061     {
00062         RD_WARN("TCP server bind fail");
00063         return false;
00064     }
00065     
00066     // Only one connection at a time as the server is single-threaded
00067     if(_serverSocket.listen(1) < 0)
00068     {
00069         RD_WARN("TCP server listen fail");
00070         return false;
00071     }
00072     RD_INFO("TCP server is listening...");
00073     _initOk = true;
00074     return true;
00075 }
00076 
00077 // Run - never returns so run in a thread
00078 void RdWebServer::run()
00079 {
00080     // Check initialised ok
00081     if (!_initOk)
00082         return;
00083 
00084     // Start accepting connections
00085     RD_INFO("Waiting for TCP connection");
00086     while (true)
00087     {
00088         // Accept connection if available
00089         TCPSocketConnection clientSocketConn;
00090         clientSocketConn.set_blocking(_blockingOnAccept, _timeoutOnBlocking);
00091         _serverSocket.accept(clientSocketConn);
00092         if (!clientSocketConn.is_connected())
00093             continue;
00094         
00095         // Connection
00096         RD_INFO("Connection from IP: %s", clientSocketConn.get_address());
00097         if (_pStatusLed != NULL)
00098             *_pStatusLed = true;
00099         
00100         // While connected
00101         bool forcedClosed = false;
00102         _curSplitPayloadPos = -1;
00103         while(clientSocketConn.is_connected() && !forcedClosed)
00104         {
00105             // Receive data
00106             if (_blockingOnReceive != _blockingOnAccept)
00107                 clientSocketConn.set_blocking(_blockingOnReceive, _timeoutOnBlocking);
00108             int rxLen = clientSocketConn.receive(_buffer, HTTPD_MAX_REQ_LENGTH);
00109             if (rxLen == -1)
00110             {
00111                 if (_closeConnOnReceiveFail)
00112                 {
00113                     int closeRet = clientSocketConn.close();
00114                     RD_DBG("Rx Timeout - conn close() ret %d (is_connected %d)", closeRet, clientSocketConn.is_connected());
00115                     forcedClosed = true;
00116                 }
00117                 else
00118                 {
00119                     RD_DBG("Rx Timeout - not closing - is_connected %d", clientSocketConn.is_connected());
00120                 }
00121                 continue;
00122             }
00123             if (rxLen == 0)
00124             {
00125                 RD_DBG("clientSocketConn.receive() returned %d - ignoring -  is connected %d", rxLen, clientSocketConn.is_connected());
00126                 continue;
00127             }
00128             
00129             // Handle received message
00130             _buffer[rxLen] = '\0';
00131             _bufferReceivedLen = rxLen;
00132             handleReceivedHttp(clientSocketConn);
00133             
00134             // Close connection if required
00135             if (_closeConnAfterSend)
00136             {
00137                 int closeRet = clientSocketConn.close();
00138                 RD_DBG("After send connection close() ret %d is connected %d", closeRet, clientSocketConn.is_connected());
00139                 forcedClosed = true;
00140             }
00141         }
00142         
00143         // Waiting again ...
00144         RD_INFO("Waiting for TCP connection");
00145     }
00146 }
00147 
00148 // Handle a request            
00149 bool RdWebServer::handleReceivedHttp(TCPSocketConnection &clientSocketConn)
00150 {
00151     bool handledOk = false;
00152     
00153     // Check for split payload
00154     if (_curSplitPayloadPos != -1)
00155     {
00156         // Handle remaining parts of content
00157         char* respStr = (_curWebServerCmdDef->_callback)(_curHttpMethod, _curCmdStr, _curArgStr, _buffer, _bufferReceivedLen, 
00158                         _curContentLen, (unsigned char*)_buffer, _bufferReceivedLen, _curSplitPayloadPos);
00159         RD_DBG("Received part of message - content %d - rx %d - splitAfter %d", _curContentLen, _bufferReceivedLen, _curSplitPayloadPos);
00160         _curSplitPayloadPos += _bufferReceivedLen;
00161         // Check if all received
00162         if (_curSplitPayloadPos >= _curContentLen)
00163         {
00164             _curSplitPayloadPos = -1;
00165             clientSocketConn.send_all(respStr, strlen(respStr));
00166             RD_DBG("That was the end of message - content %d - rx %d", _curContentLen, _bufferReceivedLen);
00167         }
00168         return true;
00169     }
00170 
00171     // Get payload information    
00172     int payloadLen = -1;
00173     unsigned char* pPayload = getPayloadDataFromMsg(_buffer, _bufferReceivedLen, payloadLen);
00174     
00175     // Debug
00176     int displayLen = _bufferReceivedLen;
00177     if (payloadLen > 0)
00178         displayLen = _bufferReceivedLen-payloadLen;
00179     RD_DBG("\r\nNEW REQUEST RxLen %d ContentLen %d PayloadLen %d\n\r\n\r%.*s", _bufferReceivedLen, _curContentLen, payloadLen, displayLen, _buffer);
00180     
00181     // Get HTTP method
00182     _curHttpMethod = METHOD_OTHER;
00183     if (strncmp(_buffer, "GET ", 4) == 0)
00184         _curHttpMethod = METHOD_GET;
00185     else if (strncmp(_buffer, "POST", 4) == 0)
00186         _curHttpMethod = METHOD_POST;
00187     else if (strncmp(_buffer, "OPTIONS", 7) == 0)
00188         _curHttpMethod = METHOD_OPTIONS;
00189 
00190     // See if there is a valid HTTP command
00191     _curContentLen = -1;
00192     if (extractCmdArgs(_buffer+3, _curCmdStr, MAX_CMDSTR_LEN, _curArgStr, MAX_ARGSTR_LEN, _curContentLen))
00193     {
00194         RD_DBG("CmdStr %s", _curCmdStr);
00195         RD_DBG("ArgStr %s", _curArgStr);
00196 
00197         bool cmdFound = false;
00198         for (int wsCmdIdx = 0; wsCmdIdx < _numWebServerCmds; wsCmdIdx++)
00199         {
00200             RdWebServerCmdDef* pCmd = _pWebServerCmds[wsCmdIdx];
00201             if (strcasecmp(pCmd->_pCmdStr, _curCmdStr) == 0)
00202             {
00203                 RD_DBG("FoundCmd <%s> Type %d", _curCmdStr, pCmd->_cmdType);
00204                 cmdFound = true;
00205                 if (pCmd->_cmdType == RdWebServerCmdDef::CMD_CALLBACK)
00206                 {
00207                     char* respStr = (pCmd->_callback)(_curHttpMethod, _curCmdStr, _curArgStr, _buffer, _bufferReceivedLen, 
00208                                     _curContentLen, pPayload, payloadLen, 0);
00209                     // Handle split-payload situation
00210                     if (_curContentLen > 0 && payloadLen < _curContentLen)
00211                     {
00212                         _curSplitPayloadPos = payloadLen;
00213                         _curWebServerCmdDef = pCmd;
00214                     }
00215                     else
00216                     {
00217                         clientSocketConn.send_all(respStr, strlen(respStr));
00218                     }
00219                     handledOk = true;
00220                 }
00221                 else if ( (pCmd->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE) ||
00222                           (pCmd->_cmdType == RdWebServerCmdDef::CMD_SDORUSBFILE) )
00223                 {
00224                     char combinedFileName[MAX_FILENAME_LEN];
00225                     strcpy(combinedFileName, pCmd->_substFileName);
00226                     if (strlen(combinedFileName) == 0)
00227                         strcpy(combinedFileName, _curCmdStr);
00228                     else if (combinedFileName[strlen(combinedFileName)-1] == '*')
00229                         strcpy(combinedFileName+strlen(combinedFileName)-1, _curArgStr);
00230                     if (pCmd->_cmdType == RdWebServerCmdDef::CMD_LOCALFILE)
00231                         handledOk = handleLocalFileRequest(combinedFileName, _curArgStr, clientSocketConn, pCmd->_bCacheIfPossible);
00232                     else
00233                         handledOk = handleSDFileRequest(combinedFileName, _curArgStr, clientSocketConn);
00234 
00235                 }
00236                 break;
00237             }
00238         }
00239         // If command not found see if it is a local file
00240         if (!cmdFound)
00241         {
00242             char combinedFileName[MAX_FILENAME_LEN];
00243             strcpy(combinedFileName, _curCmdStr);
00244             if (strlen(_curArgStr) > 0)
00245             {
00246                 strcat(combinedFileName, "/");
00247                 strcat(combinedFileName, _curArgStr);
00248             }
00249             handledOk = handleSDFileRequest(combinedFileName, _curArgStr, clientSocketConn);
00250         }
00251     }
00252     else
00253     {
00254         RD_DBG("Cannot find command or args\r\n");
00255     }
00256     return handledOk;
00257 }
00258 
00259 // Add a command to the server
00260 void RdWebServer::addCommand(char* pCmdStr, int cmdType, CmdCallbackType callback, char* substFileName, bool cacheIfPossible)
00261 {
00262     // Check for overflow
00263     if (_numWebServerCmds >= MAX_WEB_SERVER_CMDS)
00264         return;
00265         
00266     // Create new command definition and add
00267     RdWebServerCmdDef* pNewCmdDef = new RdWebServerCmdDef(pCmdStr, cmdType, callback, substFileName, cacheIfPossible);
00268     _pWebServerCmds[_numWebServerCmds] = pNewCmdDef;
00269     _numWebServerCmds++;
00270 }
00271 
00272 // Form a header to respond
00273 void RdWebServer::formHTTPHeader(const char* rsltCode, const char* contentType, int contentLen)
00274 {
00275     const char* closeConnStr = "\r\nConnection: keep-alive";
00276     if(contentLen != -1)
00277         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 : "");
00278     else
00279         sprintf(_httpHeader, "HTTP/1.1 %s\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: %s%s\r\n\r\n", rsltCode, contentType, _closeConnAfterSend ? closeConnStr : "");
00280 }
00281 
00282 // Use file extension to determine MIME type
00283 char* getMimeTypeStr(char* filename)
00284 {
00285     char* mimeType = "text/plain";
00286     char *pDot = strrchr(filename, '.');
00287     if (pDot && (!strcmp(pDot, ".html") || !strcmp(pDot, ".htm")))
00288         mimeType = "text/html";
00289     else if (pDot && !strcmp(pDot, ".css"))
00290         mimeType = "text/css";
00291     else if (pDot && !strcmp(pDot, ".js"))
00292         mimeType = "application/javascript";
00293     else if (pDot && !strcmp(pDot, ".png"))
00294         mimeType = "image/png";
00295     else if (pDot && (!strcmp(pDot, ".jpeg") || !strcmp(pDot, ".jpeg")))
00296         mimeType = "image/jpeg";
00297     return mimeType;
00298 }
00299 
00300 // Handle request for files/listing from SDCard
00301 bool RdWebServer::handleSDFileRequest(char* inFileName, char* argStr, TCPSocketConnection &clientSocketConn)
00302 {
00303 #ifdef SUPPORT_SD_FILESYSTEM
00304 
00305     bool handledOk = false;
00306     const int HTTPD_MAX_FNAME_LENGTH = 127;
00307     char filename[HTTPD_MAX_FNAME_LENGTH+1];
00308     
00309     RD_INFO("Requesting file %s", inFileName);
00310     
00311 #ifdef SUPPORT_FOLDER_VIEW
00312     if ((strlen(inFileName) > 0) && (inFileName[strlen(inFileName)-1] == '/'))
00313     {
00314         RD_INFO("Request directory %s%s", _pBaseWebFolder, inFileName);
00315         sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
00316         
00317         // Obtain lock on SD card (if reqd)
00318         if (_pSdCardMutex)
00319             _pSdCardMutex->lock();
00320             
00321         DIR *d = opendir(filename);
00322         if (d != NULL) 
00323         {
00324             formHTTPHeader("200 OK", "text/html", -1);
00325             clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00326             sprintf(_httpHeader,"<html><head><title>Directory Listing</title></head><body><h1>%s</h1><ul>", inFileName);
00327             clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00328             struct dirent *p;
00329             while((p = readdir(d)) != NULL) 
00330             {
00331                 RD_INFO("%s", p->d_name);
00332                 sprintf(_httpHeader,"<li>%s</li>", p->d_name);
00333                 clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00334             }
00335         }
00336         closedir(d);
00337         
00338         // Release lock on SD card (if reqd)
00339         if (_pSdCardMutex)
00340             _pSdCardMutex->unlock();
00341 
00342         RD_DBG("Directory closed\n");
00343         sprintf(_httpHeader,"</ul></body></html>");
00344         clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00345         handledOk = true;
00346     }
00347     else
00348 #endif
00349     {
00350         sprintf(filename, "%s%s", _pBaseWebFolder, inFileName);
00351         RD_INFO("Filename %s", filename);
00352             
00353         // Obtain lock on SD card (if reqd)
00354         if (_pSdCardMutex)
00355             _pSdCardMutex->lock();
00356 
00357         FILE* fp = fopen(filename, "r");
00358         if (fp == NULL)
00359         {
00360             RD_WARN("Filename %s not found", filename);
00361             formHTTPHeader("404 Not Found", "text/plain", 0);
00362             clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00363             handledOk = true;
00364         }
00365         else
00366         {
00367             RD_INFO("Sending file %s", filename);
00368             // Find file length
00369             fseek(fp, 0L, SEEK_END);
00370             int sz = ftell(fp);
00371             fseek(fp, 0L, SEEK_SET);
00372             // Get mime type
00373             char* mimeType = getMimeTypeStr(filename);
00374             RD_DBG("MIME TYPE %s", mimeType);
00375             // Form header   
00376             formHTTPHeader("200 OK", mimeType, sz);
00377             clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00378             // Read file in blocks and send
00379             int rdCnt = 0;
00380             char fileBuf[1024];
00381             while ((rdCnt = fread(fileBuf, sizeof( char ), 1024, fp)) == 1024) 
00382             {
00383                 clientSocketConn.send_all(fileBuf, rdCnt);
00384             }
00385             clientSocketConn.send_all(fileBuf, rdCnt);
00386             fclose(fp);
00387             handledOk = true;
00388         }
00389         
00390         // Obtain lock on SD card (if reqd)
00391         if (_pSdCardMutex)
00392             _pSdCardMutex->unlock();
00393 
00394     }
00395     return handledOk;
00396     
00397 #else // support SUPPORT_SD_FILESYSTEM
00398 
00399     return false;
00400     
00401 #endif
00402 }
00403 
00404 // Send a file from cache - used for local files only
00405 #ifdef SUPPORT_LOCAL_FILE_CACHE
00406 void RdWebServer::sendFromCache(RdFileCacheEntry* pCacheEntry, TCPSocketConnection &clientSocketConn)
00407 {
00408     RD_INFO("Sending file %s from cache %d bytes", pCacheEntry->_fileName, pCacheEntry->_nFileLen);
00409     // Get mime type
00410     char* mimeType = getMimeTypeStr(pCacheEntry->_fileName);
00411     RD_INFO("MIME TYPE %s", mimeType);
00412     // Form header
00413     formHTTPHeader("200 OK", mimeType, pCacheEntry->_nFileLen);
00414     clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00415     char* pMem = pCacheEntry->_pFileContent;
00416     int nLenLeft = pCacheEntry->_nFileLen;
00417     int blkSize = 2048;
00418     while(nLenLeft > 0)
00419     {
00420         if (blkSize > nLenLeft)
00421             blkSize = nLenLeft;
00422         clientSocketConn.send_all(pMem, blkSize);
00423         pMem += blkSize;
00424         nLenLeft -= blkSize;
00425     }
00426 }
00427 #endif
00428 
00429 // Handle a request for a local file
00430 bool RdWebServer::handleLocalFileRequest(char* inFileName, char* argStr, TCPSocketConnection &clientSocketConn, bool bCacheIfPossible)
00431 {
00432 
00433 #ifdef SUPPORT_LOCAL_FILESYSTEM
00434 
00435     const int HTTPD_MAX_FNAME_LENGTH = 127;
00436     char localFilename[HTTPD_MAX_FNAME_LENGTH+1];
00437     char reqFileNameStr[HTTPD_MAX_FNAME_LENGTH+1];
00438 
00439     RD_INFO("Requesting local file %s", inFileName);
00440     sprintf(reqFileNameStr, "/%s", inFileName);
00441     sprintf(localFilename, "/local/%s", inFileName);
00442         
00443     if (bCacheIfPossible)
00444     {
00445         // Check if file already cached
00446         bool bTryToCache = true;
00447         for (int wsCacheIdx = 0; wsCacheIdx < _numWebServerCachedFiles; wsCacheIdx++)
00448         {
00449             RdFileCacheEntry* pCachedFile = _pWebServerCachedFiles[wsCacheIdx];
00450             if (strcmp(inFileName, pCachedFile->_fileName) == 0)
00451             {
00452                 if (pCachedFile->_bCacheValid)
00453                 {
00454                     sendFromCache(pCachedFile, clientSocketConn);
00455                     return true;
00456                 }
00457                 bTryToCache = false; // don't try to cache as cacheing must have already failed
00458             }
00459         }
00460         
00461         // Check for cache full
00462         if (_numWebServerCachedFiles >= MAX_WEB_SERVER_CACHED_FILES)
00463             bTryToCache = false;
00464             
00465         // See if we can cache the file
00466         if (bTryToCache)
00467         {
00468             RdFileCacheEntry* pCacheEntry = new RdFileCacheEntry(inFileName);
00469             if (pCacheEntry)
00470             {
00471                 bool bCacheSuccess = pCacheEntry->readLocalFileIntoCache(localFilename);
00472 
00473                 // Store the cache entry even if reading failed (mem alloc or file not found, etc) so we don't try to cache again
00474                 _pWebServerCachedFiles[_numWebServerCachedFiles] = pCacheEntry;
00475                 _numWebServerCachedFiles++;
00476                 if (bCacheSuccess)
00477                 {
00478                     sendFromCache(pCacheEntry, clientSocketConn);
00479                     return true;
00480                 }
00481             }
00482         }        
00483     }
00484     
00485     LocalFileSystem local("local");
00486     
00487     FILE* fp = fopen(localFilename, "r");
00488     if (fp == NULL)
00489     {
00490         RD_WARN("Local file %s not found", localFilename);
00491         formHTTPHeader("404 Not Found", "text/plain", 0);
00492         clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00493         return true;
00494     }
00495     else
00496     {
00497         RD_INFO("Sending file %s from disk", localFilename);
00498         // Find file length
00499         fseek(fp, 0L, SEEK_END);
00500         int sz = ftell(fp);
00501         fseek(fp, 0L, SEEK_SET);
00502         // Get mime type
00503         char* mimeType = getMimeTypeStr(localFilename);
00504         RD_DBG("MIME TYPE %s", mimeType);
00505         // Form header   
00506         formHTTPHeader("200 OK", mimeType, sz);
00507         clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00508         int rdCnt = 0;
00509         while ((rdCnt = fread(_httpHeader, sizeof( char ), sizeof(_httpHeader), fp)) == sizeof(_httpHeader)) 
00510         {
00511             clientSocketConn.send_all(_httpHeader, rdCnt);
00512         }
00513         if (rdCnt != 0)
00514             clientSocketConn.send_all(_httpHeader, rdCnt);
00515         fclose(fp);
00516         return true;
00517     }
00518     
00519 #else
00520 
00521     RD_WARN("Local file system not supported");
00522     formHTTPHeader("404 Not Found", "text/plain", 0);
00523     clientSocketConn.send_all(_httpHeader,strlen(_httpHeader));
00524     return true;
00525 
00526 #endif
00527 }
00528 
00529 // Read file into cache
00530 #ifdef SUPPORT_LOCAL_FILE_CACHE
00531 bool RdFileCacheEntry::readLocalFileIntoCache(char* fileName)
00532 {
00533 #ifdef SUPPORT_LOCAL_FILESYSTEM
00534     
00535     RD_INFO("Reading into cache %s", fileName);
00536     LocalFileSystem local("local");
00537     FILE* fp = fopen(fileName, "r");
00538     if (fp == NULL)
00539     {
00540         RD_WARN("Failed to open file");
00541         return false;
00542     }
00543     RD_DBG("Seeking ");
00544     fseek(fp, 0, SEEK_END);
00545     _nFileLen = (int)ftell(fp);
00546     RD_DBG("Len %d ", _nFileLen);
00547     _pFileContent = new char[_nFileLen];
00548     RD_DBG("Buf %08x ", _pFileContent);
00549     if (!_pFileContent)
00550     {
00551         RD_WARN("Failed to allocate %lu", _nFileLen);
00552         fclose(fp);
00553         return false;
00554     }
00555     RD_DBG("Allocated");
00556     memset(_pFileContent, 0, _nFileLen);
00557     fseek(fp, 0, SEEK_SET);
00558     char* pMem = _pFileContent;
00559     char fileBuf[100];
00560     int totCnt = 0;
00561     int rdCnt = 0;
00562     RD_DBG("Reading");
00563     while (true)
00564     {
00565         int toRead = _nFileLen - totCnt;
00566         if (toRead > sizeof(fileBuf))
00567             toRead = sizeof(fileBuf);
00568         if (toRead <= 0)
00569             break;
00570         rdCnt = fread(fileBuf, sizeof(char), toRead, fp);
00571         if (rdCnt <= 0)
00572             break;
00573         RD_DBG("Read %d tot %d of %d", rdCnt, totCnt, _nFileLen);
00574         memcpy(pMem, fileBuf, rdCnt);
00575         pMem += rdCnt;
00576         totCnt += rdCnt;
00577     }
00578     RD_DBG("Done read");
00579     fclose(fp);
00580     RD_DBG("Success in caching %d bytes (read %d)", _nFileLen, totCnt);
00581     _bCacheValid = true;
00582     return true;
00583 #else
00584     return false;
00585 #endif
00586 }
00587 
00588 #endif
00589 
00590 // Extract arguments from command
00591 bool RdWebServer::extractCmdArgs(char* buf, char* pCmdStr, int maxCmdStrLen, char* pArgStr, int maxArgStrLen, int& contentLen)
00592 {
00593     contentLen = -1;
00594     *pCmdStr = '\0';
00595     *pArgStr = '\0';
00596     int cmdStrLen = 0;
00597     int argStrLen = 0;
00598     if (buf == NULL)
00599         return false;
00600     // Check for Content-length header
00601     char* contentLenText = "Content-Length:";
00602     char* pContLen = strstr(buf, contentLenText);
00603     if (pContLen)
00604     {
00605         if (*(pContLen + strlen(contentLenText)) != '\0')
00606             contentLen = atoi(pContLen + strlen(contentLenText));
00607     }
00608     
00609     // Check for first slash
00610     char* pSlash1 = strchr(buf, '/');
00611     if (pSlash1 == NULL)
00612         return false;
00613     pSlash1++;
00614     // Extract command
00615     while(*pSlash1)
00616     {
00617         if (cmdStrLen >= maxCmdStrLen-1)
00618             break;
00619         if ((*pSlash1 == '/') || (*pSlash1 == ' ') || (*pSlash1 == '\n') || (*pSlash1 == '?') || (*pSlash1 == '&'))
00620             break;
00621         *pCmdStr++ = *pSlash1++;
00622         *pCmdStr = '\0';
00623         cmdStrLen++;
00624     }
00625     if ((*pSlash1 == '\0') || (*pSlash1 == ' ') || (*pSlash1 == '\n'))
00626         return true;
00627     // Now args
00628     *pSlash1++;
00629     while(*pSlash1)
00630     {
00631         if (argStrLen >= maxArgStrLen-1)
00632             break;
00633         if ((*pSlash1 == ' ') || (*pSlash1 == '\n'))
00634             break;
00635         *pArgStr++ = *pSlash1++;
00636         *pArgStr = '\0';
00637         argStrLen++;
00638     }
00639     return true;
00640 }
00641 
00642 unsigned char* RdWebServer::getPayloadDataFromMsg(char* msgBuf, int msgLen, int& payloadLen)
00643 {
00644     payloadLen = -1;
00645     char* ptr = strstr(msgBuf, "\r\n\r\n");
00646     if (ptr)
00647     {
00648         payloadLen = msgLen - (ptr+4-msgBuf);
00649         return (unsigned char*) (ptr+4);
00650     }
00651     return NULL;
00652 }
00653 
00654 int RdWebServer::getContentLengthFromMsg(char* msgBuf)
00655 {
00656     char* ptr = strstr(msgBuf, "Content-Length:");
00657     if (ptr)
00658     {
00659         ptr += 15;
00660         int contentLen = atoi(ptr);
00661         if (contentLen >= 0)
00662             return contentLen;
00663     }
00664     return 0;
00665 }