From bd5afe45929c531892533f6fac4fc083eb0cb225 Mon Sep 17 00:00:00 2001 From: anschrammh Date: Thu, 4 Apr 2019 07:56:37 +0200 Subject: [PATCH] Added Dictionary string entity class for char * manipulation, completed webApi, updated main app and other small things --- src/app/Dictionary.h | 79 +++++++++++++++++++++++++++++------- src/app/WEBServerManager.cpp | 65 +++++++++++++++++++++++++---- src/app/WEBServerManager.h | 4 +- src/app/app.ino | 9 ++-- src/app/webApi.cpp | 27 +++++++++--- src/app/webApi.h | 2 + 6 files changed, 155 insertions(+), 31 deletions(-) diff --git a/src/app/Dictionary.h b/src/app/Dictionary.h index 1b30e39..d11a2fc 100644 --- a/src/app/Dictionary.h +++ b/src/app/Dictionary.h @@ -6,6 +6,36 @@ #include #include +namespace DictionaryHelper +{ + //String helper class with c style char array + class StringEntity + { + public: + StringEntity(const char *string) : _string(NULL) + { + if(string == NULL) + { + _string = (char *) malloc((sizeof(char)) * 2); //+1 for the string terminating character + strcpy(_string, ""); + } + else + { + _string = (char *) malloc((strlen(string) * sizeof(char)) + 1); //+1 for the string terminating character + strcpy(_string, string); + } + } + StringEntity(const StringEntity &Object) + { + _string = (char *) malloc((strlen(Object._string) * sizeof(char)) + 1); //+1 for the string terminating character + strcpy(_string, Object._string); + } + ~StringEntity(){free(_string);} + char *getString(){return _string;} + private: + char *_string; + }; +} template class Dictionary @@ -13,6 +43,25 @@ class Dictionary public: Dictionary() :_parameter(NULL), _value(NULL), _next(NULL), _head(this){} + Dictionary(Dictionary const& dictionaryToCopy) //Copy constructor needed because of pointers + { + _head = this; + _next = NULL; + + if(dictionaryToCopy._parameter != NULL) + { + _parameter = (char *) malloc((strlen(dictionaryToCopy._parameter) * sizeof(char)) + 1); //+1 for the string terminating character + _value = new T(*(dictionaryToCopy._value)); + + strcpy(_parameter, dictionaryToCopy._parameter); + }else + { + _parameter = NULL; + _value = NULL; + } + + } + ~Dictionary() { if(_head == this) @@ -133,9 +182,22 @@ public: } const char *stringValue() const {return _value == NULL ? "" : _value->toString();} - T getValue(){return T(*_value);} - T* getValueRef(){return _value;} - const char *getParameter() const{return _parameter == NULL ? "" : _parameter;} + const char *getParameter(const unsigned int index) + { + unsigned int position(0); + if(isListEmpty(_head->_next))return ""; + + Dictionary *cursor = _head->_next; + + while(!isListEmpty(cursor)) + { + if(position++ == index) + return cursor->_parameter; + cursor = cursor->_next; + } + + return ""; + } protected: Dictionary(const char *parameter, T *value) : Dictionary() { @@ -146,17 +208,6 @@ protected: _value = value; } - Dictionary(Dictionary const& dictionaryToCopy) //Copy constructor needed because of pointers - { - _head = NULL; - _next = NULL; - - _parameter = (char *) malloc((strlen(dictionaryToCopy._parameter) * sizeof(char)) + 1); //+1 for the string terminating character - _value = dictionaryToCopy._value; - - strcpy(_parameter, dictionaryToCopy._parameter); - } - boolean addNewNodeAtTheEnd(Dictionary *node) { if(node == NULL) return false; diff --git a/src/app/WEBServerManager.cpp b/src/app/WEBServerManager.cpp index 304a521..2c747c3 100644 --- a/src/app/WEBServerManager.cpp +++ b/src/app/WEBServerManager.cpp @@ -3,7 +3,7 @@ #define DEBUG #define DEBUG_RAW -WEBServerManager::WEBServerManager(unsigned int port, SDCardManager *sdCardManager) : _wifiServer(port), _sdCardManager(sdCardManager), _httpRequestData({UNDEFINED, UNKNOWN, UNKNOWN_MIME, NULL,NULL}), _httpParserState(INIT), _clientState(WAITING_FOR_CLIENT), _port(port), _clientTimeout(0) +WEBServerManager::WEBServerManager(unsigned int port, SDCardManager *sdCardManager) : _wifiServer(port), _sdCardManager(sdCardManager), _httpRequestData({UNDEFINED, UNKNOWN, UNKNOWN_MIME, Dictionary(), Dictionary(), NULL,NULL}), _httpParserState(INIT), _clientState(WAITING_FOR_CLIENT), _port(port), _clientTimeout(0) { _wifiServer.begin(); } @@ -82,11 +82,12 @@ boolean WEBServerManager::runServer() boolean WEBServerManager::parseQuery(WiFiClient *wifiClient) { - char readChar(0), *parseBuffer(NULL); - boolean smallTimeout(false); + char readChar(0), *parseBuffer(NULL), *parseKey(NULL), *parseValue(NULL); + boolean smallTimeout(false), isKey(true); _httpParserState = INIT; _clientTimeout = millis(); + boolean slashesOrantiSlashesOnly(true); while(wifiClient->available() || millis() - _clientTimeout < (smallTimeout ? 100 : 5000)) { if(wifiClient->available()) @@ -131,18 +132,60 @@ boolean WEBServerManager::parseQuery(WiFiClient *wifiClient) _httpParserState = ERROR; break; case HTTP_RESOURCE_SECTION: - if(readChar != ' ') + if(readChar == '?' ) + { + free(_httpRequestData.httpResource);_httpRequestData.httpResource = NULL; + _httpRequestData.httpResource = parseBuffer;parseBuffer = NULL; + + _httpParserState = HTTP_RESOURCE_PARAM_SECTION; + } + else if(readChar != ' ') { + //if(readChar != '/' && readChar != '\\') slashesOrantiSlashesOnly = false; + parseBuffer = addChar(parseBuffer, readChar); _httpParserState = HTTP_RESOURCE_SECTION; } else { free(_httpRequestData.httpResource);_httpRequestData.httpResource = NULL; - _httpRequestData.httpResource = parseBuffer;parseBuffer = NULL; - _httpParserState = HTTP_VER_SECTION; + if(slashesOrantiSlashesOnly) + { + free(parseBuffer);parseBuffer = NULL; + _httpRequestData.httpResource = (char *) malloc(sizeof(char)*2); + strcpy(_httpRequestData.httpResource,"/"); + } + else + _httpRequestData.httpResource = parseBuffer;parseBuffer = NULL; + + _httpParserState = HTTP_VER_SECTION; } break; + case HTTP_RESOURCE_PARAM_SECTION: + if(readChar == ' ') + { + _httpRequestData.getParams.add(parseKey,new DictionaryHelper::StringEntity(parseValue)); + free(parseKey);free(parseValue); + parseKey = NULL;parseValue = NULL; + _httpParserState = HTTP_VER_SECTION; + } + else if( readChar == '=') + isKey = false; + else if(readChar == '&') + { + isKey = true; + _httpRequestData.getParams.add(parseKey, new DictionaryHelper::StringEntity(parseValue)); + free(parseKey);free(parseValue); + parseKey = NULL;parseValue = NULL; + } + else + { + if(isKey) + parseKey = addChar(parseKey, readChar); + else + parseValue = addChar(parseValue, readChar); + } + break; case HTTP_VER_SECTION: if((readChar >= 48 && readChar <= 57) || readChar == '.') { @@ -194,6 +237,11 @@ boolean WEBServerManager::parseQuery(WiFiClient *wifiClient) Serial.println(_httpRequestData.HV); Serial.print("BODY CONTENT : "); Serial.println(_httpRequestData.httpBody); + Serial.println("GET PARAMS :"); + for(int i = 0; i < _httpRequestData.getParams.count(); i++) + { + Serial.print(_httpRequestData.getParams.getParameter(i));Serial.print(" : ");Serial.println(_httpRequestData.getParams(i)->getString()); + } #endif return true; @@ -323,8 +371,9 @@ boolean WEBServerManager::sendPageToClientFromSdCard(WiFiClient *wifiClient) boolean WEBServerManager::sendPageToClientFromApiDictio(WiFiClient *wifiClient) { - if(_apiDictionary.count() == 0) + if(_apiDictionary.count() == 0 || _httpRequestData.httpResource == NULL) return false; + ApiRoutine *ref = _apiDictionary(_httpRequestData.httpResource); if(ref == NULL) @@ -441,5 +490,5 @@ void WEBServerManager::clearHttpRequestData() _httpRequestData.HMT = UNKNOWN_MIME; free(_httpRequestData.httpResource);free(_httpRequestData.httpBody); _httpRequestData.httpResource = NULL;_httpRequestData.httpBody = NULL; - + _httpRequestData.getParams.dispose(); } diff --git a/src/app/WEBServerManager.h b/src/app/WEBServerManager.h index 9ec3e53..a5ab83a 100644 --- a/src/app/WEBServerManager.h +++ b/src/app/WEBServerManager.h @@ -15,12 +15,14 @@ class WEBServerManager enum ClientStatus {NOT_HANDLED, HANDLED, NEW, WAITING_FOR_CLIENT, QUERY_PARSED, RESPONSE_SENT}; enum HttpRequestMethod {UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH}; enum HttpVersion {UNKNOWN, HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0}; - enum HttpParserStatus {INIT, LINE_BREAK, HTTP_VERB_SECTION, HTTP_RESOURCE_SECTION, HTTP_VER_SECTION, PARAMETER_SECTION, BODY_SECTION, IGNORED, ERROR}; + enum HttpParserStatus {INIT, LINE_BREAK, HTTP_VERB_SECTION, HTTP_RESOURCE_SECTION, HTTP_RESOURCE_PARAM_SECTION, HTTP_VER_SECTION, PARAMETER_SECTION, BODY_SECTION, IGNORED, ERROR}; enum HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG}; struct HttpRequestData{ HttpRequestMethod HRM; HttpVersion HV; HttpMIMEType HMT; + Dictionary getParams; + Dictionary postParams; char *httpResource; char *httpBody; }; diff --git a/src/app/app.ino b/src/app/app.ino index 719a773..1881e7b 100644 --- a/src/app/app.ino +++ b/src/app/app.ino @@ -16,6 +16,8 @@ ViewSTAPacket vstap = {sab.getConnectivityManager().macAddress(), sab.getConnect void setup() { // put your setup code here, to run once: + pinMode(GPIO_0, INPUT); + Serial.println("Starting setup"); CFGFileParser cfgFileParser(sab.getSdCardManager(), AP_CFG_FILE); CFGDictionary *cfgDictionary = (CFGDictionary *) cfgFileParser.parseFile(); @@ -23,8 +25,6 @@ void setup() Serial.print("AP PASSWORD : ");if((*cfgDictionary)("PASSWORD") != NULL)Serial.println((*cfgDictionary)("PASSWORD")->stringValue()); delete cfgDictionary; - - pinMode(GPIO_0, INPUT); sab.getScreenManager().addView(&(view_1), &v1p, 0); sab.getScreenManager().addView(&(view_2), &vap, 1); sab.getScreenManager().addView(&(view_3), &vstap, 2); @@ -34,7 +34,10 @@ void setup() Serial.println("Clock lost power"); sab.getRtcManager().setDateTime(DateTime(F(__DATE__), F(__TIME__))); } - sab.getWebServerManager().addApiRoutine("/hello", &(helloServerApi), &sab); + + sab.getWebServerManager().addApiRoutine("/helloServer", &(helloServerApi), NULL); + sab.getWebServerManager().addApiRoutine("/view/next", &(nextViewApi), &sab, WEBServerManager::GET); + sab.getWebServerManager().addApiRoutine("/rtc/get/time", &(rtcTimeApi), &sab, WEBServerManager::GET); Serial.println("End setup"); } diff --git a/src/app/webApi.cpp b/src/app/webApi.cpp index 9bee662..b4e3adc 100644 --- a/src/app/webApi.cpp +++ b/src/app/webApi.cpp @@ -1,12 +1,29 @@ #include "SAB.h" #include "webApi.h" -boolean helloServerApi(WEBServerManager::HttpRequestData& HRD, WiFiClient* wc, void* pData) +boolean helloServerApi(WEBServerManager::HttpRequestData &HRD, WiFiClient* wc, void* pData) { - SAB *sab = (SAB *)pData; - Serial.println("Before"); - wc->print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n\r\n

Hello Client !!!

\r\n")); - Serial.println("After"); + wc->print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n\r\n

Hello client !!!

\r\n")); + return true; +} + +boolean nextViewApi(WEBServerManager::HttpRequestData &HRD, WiFiClient *wc, void *pData) +{ + SAB *p = (SAB *)pData; + char buffer[200]; + p->getScreenManager().displayNextView(); + sprintf(buffer,"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{ \"status\" : \"ok\", \"ViewUID\" : \"%d\" }", p->getScreenManager().getCurrentViewUID()); + wc->print(buffer); + return true; +} + +boolean rtcTimeApi(WEBServerManager::HttpRequestData &HRD, WiFiClient *wc, void *pData) +{ + SAB *p = (SAB *)pData; + char buffer[200]; + DateTime d = p->getRtcManager().getDateTime(); + sprintf(buffer,"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{ \"status\" : \"ok\", \"date\" : \"%d/%d/%d\", \"time\" : \"%d:%d:%d\" }", d.day(), d.month(), d.year(), d.hour(), d.minute(), d.second()); + wc->print(buffer); return true; } diff --git a/src/app/webApi.h b/src/app/webApi.h index f5e934f..73dea7f 100644 --- a/src/app/webApi.h +++ b/src/app/webApi.h @@ -3,5 +3,7 @@ #include "WebServerManager.h" boolean helloServerApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*); +boolean nextViewApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*); +boolean rtcTimeApi(WEBServerManager::HttpRequestData&, WiFiClient*, void*); #endif