From 7e6b149cd1c6ba23b481b589d287e76d230022a4 Mon Sep 17 00:00:00 2001 From: Tester23 Date: Fri, 18 Aug 2023 11:55:29 +0200 Subject: [PATCH 1/4] basic GET arguments support (not perfect, parsing could be better) --- .../HelloGetArgument/HelloGetArgument.ino | 94 +++++++++++++++++++ src/internals/HttpResource.cpp | 24 +++++ src/internals/HttpResource.hpp | 1 + 3 files changed, 119 insertions(+) create mode 100644 examples/HelloGetArgument/HelloGetArgument.ino diff --git a/examples/HelloGetArgument/HelloGetArgument.ino b/examples/HelloGetArgument/HelloGetArgument.ino new file mode 100644 index 0000000..d3d80ff --- /dev/null +++ b/examples/HelloGetArgument/HelloGetArgument.ino @@ -0,0 +1,94 @@ + +#include + +#include + + +#ifdef ESP8266 // This example is compatible with both, ATMega and ESP8266 + #include +#else + #include //! \todo Temporary see fix: https://github.com/platformio/platformio/issues/48 +// on older Arduinos use WiFi.h, on Arduino Uno R4 WiFi use WiFiS3.h + #include +#endif + +const char* ssid = "YOUR_SSID"; +const char* password = "YOUR_PASS"; + +WiFiServer wifiServer(80); + +void setup() +{ + Serial.begin(115200); + Serial.println("Starting Wifi Connection..."); + + WiFi.begin(const_cast(ssid), password); + while (WiFi.status() != WL_CONNECTED) + { + delay(500); + } + Serial.println("Connected!"); + + wifiServer.begin(); +} + +void loop() +{ + WiFiClient client( wifiServer.available() ); + if (client.connected()) + { + Serial.println("client connected!"); + // Connected to client. Allocate and initialize StreamHttpRequest object. + ArduinoHttpServer::StreamHttpRequest<1024> httpRequest(client); + + if (httpRequest.readRequest()) + { + Serial.println("Done read request!"); + + // Retrieve HTTP resource / URL requested + Serial.println( httpRequest.getResource().toString() ); + + // Retrieve 1st part of HTTP resource. + // E.g.: "api" from "/api/sensors/on" + Serial.println(httpRequest.getResource()[0]); + + ArduinoHttpServer::StreamHttpReply httpReply(client, "text/html"); + String textField = httpRequest.getResource().getArgument("textfield"); + Serial.print("Textfield is: "); + Serial.println(textField); + + String reply = "\n" + "\n" + "\n" + " Minimal HTML Page\n" + "\n" + "\n"; + if(textField.length() > 0) { + reply += "

Hello, "; + reply += textField; + reply += "!

"; + } + reply += "
\n" + "
\n" + "

\n" + " \n" + "
\n" + "\n" + ""; + httpReply.send(reply); + } + else + { + // HTTP parsing failed. Client did not provide correct HTTP data or + // client requested an unsupported feature. + ArduinoHttpServer::StreamHttpErrorReply httpReply(client, httpRequest.getContentType()); + + const char *pErrorStr( httpRequest.getError().cStr() ); + String errorStr(pErrorStr); //! \todo Make HttpReply FixString compatible. + + httpReply.send( errorStr ); + } + client.stop(); + } + +} \ No newline at end of file diff --git a/src/internals/HttpResource.cpp b/src/internals/HttpResource.cpp index 1b1064c..656d738 100644 --- a/src/internals/HttpResource.cpp +++ b/src/internals/HttpResource.cpp @@ -35,6 +35,30 @@ bool ArduinoHttpServer::HttpResource::isValid() return m_resource.length() > 0; } +// not a perfect solution, may return incorrect argument if one is a substring (at the start) of another +String ArduinoHttpServer::HttpResource::getArgument(const char *key) const { + int queryStart = m_resource.indexOf('?'); + if (queryStart == -1) { + return ""; + } + + queryStart++; + + String keyStr = String(key) + '='; + int keyStart = m_resource.indexOf(keyStr, queryStart); + + if (keyStart == -1) { + return ""; + } + + int valueEnd = m_resource.indexOf('&', keyStart); + if (valueEnd == -1) { + valueEnd = m_resource.length(); + } + + String value = m_resource.substring(keyStart + keyStr.length(), valueEnd); + return value; +} //! Retrieve resource part at the specified index. //! \details E.g. HttpResource("/api/sensors/1/state")[1] //! returns "sensors". diff --git a/src/internals/HttpResource.hpp b/src/internals/HttpResource.hpp index c7930d6..362a702 100644 --- a/src/internals/HttpResource.hpp +++ b/src/internals/HttpResource.hpp @@ -26,6 +26,7 @@ class HttpResource bool isValid(); String operator[](const unsigned int index) const; + String getArgument(const char *key) const; const String& toString() const; private: From 39c159bc3f18d777994cf4fa5793d1f7116a0e10 Mon Sep 17 00:00:00 2001 From: Tester23 Date: Tue, 22 Aug 2023 08:03:23 +0200 Subject: [PATCH 2/4] comment --- src/internals/HttpResource.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/internals/HttpResource.cpp b/src/internals/HttpResource.cpp index 656d738..98cf66e 100644 --- a/src/internals/HttpResource.cpp +++ b/src/internals/HttpResource.cpp @@ -35,7 +35,10 @@ bool ArduinoHttpServer::HttpResource::isValid() return m_resource.length() > 0; } -// not a perfect solution, may return incorrect argument if one is a substring (at the start) of another +//! Retrieve the GET argument value for given string key +//! \details E.g. res.getArgument("key") for index.php&key=value +//! returns "value". +//! \returns Empty string when index specified is out of range. String ArduinoHttpServer::HttpResource::getArgument(const char *key) const { int queryStart = m_resource.indexOf('?'); if (queryStart == -1) { @@ -44,6 +47,8 @@ String ArduinoHttpServer::HttpResource::getArgument(const char *key) const { queryStart++; + // FIXME: adding = will ensure that = is directly after key name, + // but we still may get incorrect values for strings like "akey" vs "key"... String keyStr = String(key) + '='; int keyStart = m_resource.indexOf(keyStr, queryStart); From 6215605ec21ea91e2b455f53d87c38570dbd8eaf Mon Sep 17 00:00:00 2001 From: Tester23 Date: Tue, 22 Aug 2023 08:37:56 +0200 Subject: [PATCH 3/4] add escape http characteres parsing for GET --- src/internals/HttpResource.cpp | 39 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/internals/HttpResource.cpp b/src/internals/HttpResource.cpp index 98cf66e..08047cd 100644 --- a/src/internals/HttpResource.cpp +++ b/src/internals/HttpResource.cpp @@ -34,9 +34,8 @@ bool ArduinoHttpServer::HttpResource::isValid() { return m_resource.length() > 0; } - //! Retrieve the GET argument value for given string key -//! \details E.g. res.getArgument("key") for index.php&key=value +//! \details E.g. HttpResource("/index.php&key=value").getArgument("key") //! returns "value". //! \returns Empty string when index specified is out of range. String ArduinoHttpServer::HttpResource::getArgument(const char *key) const { @@ -60,9 +59,39 @@ String ArduinoHttpServer::HttpResource::getArgument(const char *key) const { if (valueEnd == -1) { valueEnd = m_resource.length(); } - - String value = m_resource.substring(keyStart + keyStr.length(), valueEnd); - return value; +#if 0 + String ret = m_resource.substring(keyStart + keyStr.length(), valueEnd); +#else + int a, b; + String ret = ""; + for(int i = keyStart + keyStr.length(); i < valueEnd; i++) { + if (i < valueEnd-3 && (m_resource[i] == '%') && + ((a = m_resource[i+1]) && (b = m_resource[i+2])) && + (isxdigit(a) && isxdigit(b))) { + if (a >= 'a') + a -= 'a' - 'A'; + if (a >= 'A') + a -= ('A' - 10); + else + a -= '0'; + if (b >= 'a') + b -= 'a' - 'A'; + if (b >= 'A') + b -= ('A' - 10); + else + b -= '0'; + ret += (char)(16 * a + b); + i += 2; + } + else if (m_resource[i] == '+') { + ret += ' '; + } + else { + ret += m_resource[i]; + } + } +#endif + return ret; } //! Retrieve resource part at the specified index. //! \details E.g. HttpResource("/api/sensors/1/state")[1] From 26b09a7f588f7a16f98af8f555841a34ba438eea Mon Sep 17 00:00:00 2001 From: Tester23 Date: Tue, 22 Aug 2023 08:42:21 +0200 Subject: [PATCH 4/4] http escape demo sketch --- .../HTTPEscapeSequence/HTTPEscapeSequence.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 examples/HTTPEscapeSequence/HTTPEscapeSequence.cpp diff --git a/examples/HTTPEscapeSequence/HTTPEscapeSequence.cpp b/examples/HTTPEscapeSequence/HTTPEscapeSequence.cpp new file mode 100644 index 0000000..5325754 --- /dev/null +++ b/examples/HTTPEscapeSequence/HTTPEscapeSequence.cpp @@ -0,0 +1,24 @@ + +#include + + +void setup() { + // just check to see if escaped characters are parsed correctly + Serial.begin(115200); + delay(100); + Serial.println("TEST - simple"); + Serial.print("'index.php?key=value' check for key: "); + Serial.println(ArduinoHttpServer::HttpResource("index.php?key=value").getArgument("key")); + // + must get changed to space + Serial.println("TEST - with space"); + Serial.print("'action_page.php?fname=with+space&lname=' check for fname: "); + Serial.println(ArduinoHttpServer::HttpResource("action_page.php?fname=with+space&lname=").getArgument("fname")); + Serial.println("TEST - with special char"); + Serial.print("'action_page.php?fname=email%40server.com&lname=' check for fname: "); + Serial.println(ArduinoHttpServer::HttpResource("action_page.php?fname=email%40server.com&lname=").getArgument("fname")); +} + +void loop() { + // put your main code here, to run repeatedly: + +} \ No newline at end of file