A simple web server mainly based on ideas from Jasper Schuurmans Netduino web server
Dependents: RdBlindsServer SpideyWallWeb RdGasUseMonitor
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 }
Generated on Fri Jul 15 2022 15:39:19 by
