diff --git a/README.md b/README.md
index 3ba453d..13ad2ff 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,11 @@ Chunked responses are recognized and handled transparently.
---
---
+### Releases v1.0.1
+
+1. Restore cpp code besides Impl.h code to use in case of `multiple definition` linker error. Thanks to [Daniel Brunner](https://github.com/0xFEEDC0DE64) to report and make PR in [**Fixed linker errors when included in multiple .cpp files**](https://github.com/khoih-prog/AsyncHTTPRequest_Generic/pull/1). See [**HOWTO Fix `Multiple Definitions` Linker Error**](https://github.com/khoih-prog/AsyncHTTPRequest_Generic#HOWTO-Fix-Multiple-Definitions-Linker-Error)
+
+
### Releases v1.0.0
1. Initial coding to add support to **STM32F/L/H/G/WB/MP1** using built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc).
@@ -212,6 +217,19 @@ theses files must be copied into the corresponding directory:
---
---
+### HOWTO Fix `Multiple Definitions` Linker Error
+
+The current library implementation, using xyz-Impl.h instead of standard xyz.cpp, possibly creates certain `Multiple Definitions` Linker error in certain use cases. Although it's simple to just modify several lines of code, either in the library or in the application, the library is adding a separate source directory, named src_cpp, besides the standard src directory.
+
+To use the old standard cpp way, just
+
+1. **Rename the h-only src directory into src_h.**
+2. **Then rename the cpp src_cpp directory into src.**
+3. Close then reopen the application code in Arduino IDE, etc. to recompile from scratch.
+
+---
+---
+
### Examples
Also see examples:
@@ -442,7 +460,7 @@ AsyncHTTPRequest @ IP : 192.168.2.72
**************************************
abbreviation: EDT
-client_ip: 216.154.52.212
+client_ip: aaa.bbb.ccc.ddd
datetime: 2020-09-13T18:22:59.555816-04:00
day_of_week: 0
day_of_year: 257
@@ -459,7 +477,7 @@ week_number: 37
**************************************
abbreviation: EDT
-client_ip: 216.154.52.212
+client_ip: aaa.bbb.ccc.ddd
datetime: 2020-09-13T18:27:57.586325-04:00
day_of_week: 0
day_of_year: 257
@@ -489,7 +507,7 @@ After waiting 3.43 secs more in setup(), connection result is connected. Local I
H
**************************************
abbreviation: EDT
-client_ip: 216.154.52.212
+client_ip: aaa.bbb.ccc.ddd
datetime: 2020-09-13T19:35:37.951609-04:00
day_of_week: 0
day_of_year: 257
@@ -521,7 +539,7 @@ After waiting 2.35 secs more in setup(), connection result is connected. Local I
H
**************************************
abbreviation: EDT
-client_ip: 216.154.52.212
+client_ip: aaa.bbb.ccc.ddd
datetime: 2020-09-13T19:37:02.118166-04:00
day_of_week: 0
day_of_year: 257
@@ -539,7 +557,7 @@ week_number: 37
HHHHHHHHH HHHHHHHHHH HHHHHHHHHH H
**************************************
abbreviation: EDT
-client_ip: 216.154.52.212
+client_ip: aaa.bbb.ccc.ddd
datetime: 2020-09-13T19:42:01.507586-04:00
day_of_week: 0
day_of_year: 257
@@ -570,7 +588,7 @@ HTTP WebServer is @ IP : 192.168.2.81
**************************************
abbreviation: EDT
-client_ip: 216.154.52.212
+client_ip: aaa.bbb.ccc.ddd
datetime: 2020-09-13T19:56:28.295033-04:00
day_of_week: 0
day_of_year: 257
@@ -690,6 +708,10 @@ Submit issues to: [AsyncHTTPRequest_Generic issues](https://github.com/khoih-pro
---
---
+### Releases v1.0.1
+
+1. Restore cpp code besides Impl.h code to use in case of `multiple definition` linker error. Thanks to [Daniel Brunner](https://github.com/0xFEEDC0DE64) to report and make PR in [**Fixed linker errors when included in multiple .cpp files**](https://github.com/khoih-prog/AsyncHTTPRequest_Generic/pull/1). See [**HOWTO Fix `Multiple Definitions` Linker Error**](https://github.com/khoih-prog/AsyncHTTPRequest_Generic#HOWTO-Fix-Multiple-Definitions-Linker-Error)
+
### Releases v1.0.0
1. Initial coding to add support to **STM32F/L/H/G/WB/MP1** using built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc).
@@ -702,13 +724,14 @@ Submit issues to: [AsyncHTTPRequest_Generic issues](https://github.com/khoih-pro
This library is based on, modified, bug-fixed and improved from:
-1. [Bob Lemaire's asyncHTTPrequest Library](https://github.com/boblemaire/asyncHTTPrequest)
+1. [Bob Lemaire's **asyncHTTPrequest Library**](https://github.com/boblemaire/asyncHTTPrequest) to use the better **asynchronous** features of these following Async TCP Libraries : ( [`ESPAsyncTCP`](https://github.com/me-no-dev/ESPAsyncTCP), [`AsyncTCP`](https://github.com/me-no-dev/AsyncTCP), and [`STM32AsyncTCP`](https://github.com/philbowles/STM32AsyncTCP) ).
-to use the better **asynchronous** features of these following Async TCP Libraries : ( [`ESPAsyncTCP`](https://github.com/me-no-dev/ESPAsyncTCP), [`AsyncTCP`](https://github.com/me-no-dev/AsyncTCP), and [`STM32AsyncTCP`](https://github.com/philbowles/STM32AsyncTCP) ).
+2. Thanks to [Daniel Brunner](https://github.com/0xFEEDC0DE64) to report and make PR in [Fixed linker errors when included in multiple .cpp files](https://github.com/khoih-prog/AsyncHTTPRequest_Generic/pull/1) leading to v1.0.1. See [**HOWTO Fix `Multiple Definitions` Linker Error**](https://github.com/khoih-prog/AsyncHTTPRequest_Generic#HOWTO-Fix-Multiple-Definitions-Linker-Error)
diff --git a/examples/AsyncCustomHeader_STM32/AsyncCustomHeader_STM32.ino b/examples/AsyncCustomHeader_STM32/AsyncCustomHeader_STM32.ino
index 5583358..f627ba2 100644
--- a/examples/AsyncCustomHeader_STM32/AsyncCustomHeader_STM32.ino
+++ b/examples/AsyncCustomHeader_STM32/AsyncCustomHeader_STM32.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
#include "defines.h"
diff --git a/examples/AsyncCustomHeader_STM32/defines.h b/examples/AsyncCustomHeader_STM32/defines.h
index 27afabb..1c727f9 100644
--- a/examples/AsyncCustomHeader_STM32/defines.h
+++ b/examples/AsyncCustomHeader_STM32/defines.h
@@ -19,11 +19,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
/*
Currently support
diff --git a/examples/AsyncDweetGet_STM32/AsyncDweetGet_STM32.ino b/examples/AsyncDweetGet_STM32/AsyncDweetGet_STM32.ino
index bdef64f..ced0abc 100644
--- a/examples/AsyncDweetGet_STM32/AsyncDweetGet_STM32.ino
+++ b/examples/AsyncDweetGet_STM32/AsyncDweetGet_STM32.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
/**
diff --git a/examples/AsyncDweetPost_STM32/AsyncDweetPost_STM32.ino b/examples/AsyncDweetPost_STM32/AsyncDweetPost_STM32.ino
index 046e26b..feaccb8 100644
--- a/examples/AsyncDweetPost_STM32/AsyncDweetPost_STM32.ino
+++ b/examples/AsyncDweetPost_STM32/AsyncDweetPost_STM32.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
// Dweet.io POST client. Connects to dweet.io once every ten seconds, sends a POST request and a request body.
diff --git a/examples/AsyncHTTPRequest_ESP/AsyncHTTPRequest_ESP.ino b/examples/AsyncHTTPRequest_ESP/AsyncHTTPRequest_ESP.ino
index 50470c0..869b539 100644
--- a/examples/AsyncHTTPRequest_ESP/AsyncHTTPRequest_ESP.ino
+++ b/examples/AsyncHTTPRequest_ESP/AsyncHTTPRequest_ESP.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
//************************************************************************************************************
//
diff --git a/examples/AsyncHTTPRequest_ESP_WiFiManager/AsyncHTTPRequest_ESP_WiFiManager.ino b/examples/AsyncHTTPRequest_ESP_WiFiManager/AsyncHTTPRequest_ESP_WiFiManager.ino
index c1bb8f2..6e43365 100644
--- a/examples/AsyncHTTPRequest_ESP_WiFiManager/AsyncHTTPRequest_ESP_WiFiManager.ino
+++ b/examples/AsyncHTTPRequest_ESP_WiFiManager/AsyncHTTPRequest_ESP_WiFiManager.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
//************************************************************************************************************
//
diff --git a/examples/AsyncHTTPRequest_STM32/AsyncHTTPRequest_STM32.ino b/examples/AsyncHTTPRequest_STM32/AsyncHTTPRequest_STM32.ino
index bac5ad7..f728ce5 100644
--- a/examples/AsyncHTTPRequest_STM32/AsyncHTTPRequest_STM32.ino
+++ b/examples/AsyncHTTPRequest_STM32/AsyncHTTPRequest_STM32.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
//************************************************************************************************************
//
diff --git a/examples/AsyncSimpleGET_STM32/AsyncSimpleGET_STM32.ino b/examples/AsyncSimpleGET_STM32/AsyncSimpleGET_STM32.ino
index 3e89c05..fa84bd8 100644
--- a/examples/AsyncSimpleGET_STM32/AsyncSimpleGET_STM32.ino
+++ b/examples/AsyncSimpleGET_STM32/AsyncSimpleGET_STM32.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
#include "defines.h"
diff --git a/examples/AsyncWebClientRepeating_STM32/AsyncWebClientRepeating_STM32.ino b/examples/AsyncWebClientRepeating_STM32/AsyncWebClientRepeating_STM32.ino
index c5aecd8..d0ddb9a 100644
--- a/examples/AsyncWebClientRepeating_STM32/AsyncWebClientRepeating_STM32.ino
+++ b/examples/AsyncWebClientRepeating_STM32/AsyncWebClientRepeating_STM32.ino
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
#include "defines.h"
diff --git a/library.json b/library.json
index a05d600..5c90250 100644
--- a/library.json
+++ b/library.json
@@ -1,6 +1,6 @@
{
"name":"AsyncHTTPRequest_Generic",
- "version": "1.0.0",
+ "version": "1.0.1",
"description":"Simple Async HTTP Request library, supporting GET and POST, on top of AsyncTCP libraries, such as AsyncTCP, ESPAsyncTCP, AsyncTCP_STM32, etc.. for ESP32, ESP8266 and currently STM32 with built-in LAN8742A Ethernet.",
"keywords":"async,tcp,http,ESP8266,ESP32,ESPAsyncTCP,AsyncTCP,stm32,ethernet,wifi,lan8742a",
"authors": [
diff --git a/library.properties b/library.properties
index a9091bf..bc54bd9 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=AsyncHTTPRequest_Generic
-version=1.0.0
+version=1.0.1
author=Bob Lemaire,Khoi Hoang
maintainer=Khoi Hoang
license=MIT
diff --git a/src/AsyncHTTPRequest_Debug_Generic.h b/src/AsyncHTTPRequest_Debug_Generic.h
index 5825533..b6e50b4 100644
--- a/src/AsyncHTTPRequest_Debug_Generic.h
+++ b/src/AsyncHTTPRequest_Debug_Generic.h
@@ -17,15 +17,15 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
-
-#ifndef AsyncHTTPRequest_Debug_STM32_H
-#define AsyncHTTPRequest_Debug_STM32_H
+
+#pragma once
#ifdef ASYNC_HTTP_DEBUG_PORT
#define A_DBG_PORT ASYNC_HTTP_DEBUG_PORT
@@ -68,4 +68,3 @@
#define AHTTP_LOGDEBUG2(x,y,z) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.println(z); }
#define AHTTP_LOGDEBUG3(x,y,z,w) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.print(z); A_DBG_PORT.print(" "); A_DBG_PORT.println(w); }
-#endif // AsyncHTTPRequest_Debug_STM32_H
diff --git a/src/AsyncHTTPRequest_Generic.h b/src/AsyncHTTPRequest_Generic.h
index 7ab079d..2457f58 100644
--- a/src/AsyncHTTPRequest_Generic.h
+++ b/src/AsyncHTTPRequest_Generic.h
@@ -17,15 +17,15 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
-
-#ifndef AsyncHTTPRequest_Generic_h
-#define AsyncHTTPRequest_Generic_h
+
+#pragma once
#define AsyncHTTPRequest_Generic_version "1.0.0"
@@ -265,5 +265,3 @@ class AsyncHTTPRequest
};
#include "AsyncHTTPRequest_Impl_Generic.h"
-
-#endif // AsyncHTTPRequest_Generic_h
diff --git a/src/AsyncHTTPRequest_Impl_Generic.h b/src/AsyncHTTPRequest_Impl_Generic.h
index 69d2b97..853a329 100644
--- a/src/AsyncHTTPRequest_Impl_Generic.h
+++ b/src/AsyncHTTPRequest_Impl_Generic.h
@@ -17,18 +17,16 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
#pragma once
-#ifndef AsyncHTTPRequest_Impl_Generic_h
-#define AsyncHTTPRequest_Impl_Generic_h
-
//**************************************************************************************************************
AsyncHTTPRequest::AsyncHTTPRequest(): _readyState(readyStateUnsent), _HTTPcode(0), _chunked(false), _debug(DEBUG_IOTA_HTTP_SET)
@@ -529,6 +527,8 @@ bool AsyncHTTPRequest::_buildRequest()
_request->write(_URL->path);
_request->write(_URL->query);
_request->write(" HTTP/1.1\r\n");
+
+ AHTTP_LOGDEBUG3(_HTTPmethod == HTTPmethodGET ? "GET " : "POST ", _URL->path, _URL->query, " HTTP/1.1\r\n" );
delete _URL;
@@ -541,6 +541,9 @@ bool AsyncHTTPRequest::_buildRequest()
_request->write(':');
_request->write(hdr->value);
_request->write("\r\n");
+
+ AHTTP_LOGDEBUG3(hdr->name, ":", hdr->value, "\r\n" );
+
hdr = hdr->next;
}
@@ -1187,5 +1190,3 @@ char* AsyncHTTPRequest::_charstar(const __FlashStringHelper * str)
}
#endif
-
-#endif // AsyncHTTPRequest_Impl_Generic_h
diff --git a/src/utility/xbuf.h b/src/utility/xbuf.h
index debde9d..84bdab6 100644
--- a/src/utility/xbuf.h
+++ b/src/utility/xbuf.h
@@ -17,11 +17,12 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
/********************************************************************************************
@@ -44,9 +45,6 @@
********************************************************************************************/
#pragma once
-#ifndef xbuf_h
-#define xbuf_h
-
#include
struct xseg
@@ -150,4 +148,3 @@ class xbuf: public Print
#include "utility/xbuf_Impl.h"
-#endif // xbuf_h
diff --git a/src/utility/xbuf_Impl.h b/src/utility/xbuf_Impl.h
index 8ac130c..5431af6 100644
--- a/src/utility/xbuf_Impl.h
+++ b/src/utility/xbuf_Impl.h
@@ -17,17 +17,15 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
- Version: 1.0.0
+ Version: 1.0.1
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
*****************************************************************************************************************************/
-#ifndef xbuf_Impl_h
-#define xbuf_Impl_h
-
-//#include "utility/xbuf.h"
+#pragma once
xbuf::xbuf(const uint16_t segSize) : _head(nullptr), _tail(nullptr), _used(0), _free(0), _offset(0)
{
@@ -392,4 +390,3 @@ void xbuf::remSeg()
_offset = 0;
}
-#endif // xbuf_Impl_h
diff --git a/src_cpp/AsyncHTTPRequest_Debug_Generic.h b/src_cpp/AsyncHTTPRequest_Debug_Generic.h
new file mode 100644
index 0000000..de5a776
--- /dev/null
+++ b/src_cpp/AsyncHTTPRequest_Debug_Generic.h
@@ -0,0 +1,70 @@
+/****************************************************************************************************************************
+ src_cpp/AsyncHTTPRequest_Debug_Generic.h - Dead simple AsyncHTTPRequest for ESP8266, ESP32 and currently STM32 with built-in LAN8742A Ethernet
+
+ For ESP8266, ESP32 and STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncHTTPRequest_STM32 is a library for the ESP8266, ESP32 and currently STM32 run built-in Ethernet WebServer
+
+ Based on and modified from asyncHTTPrequest Library (https://github.com/boblemaire/asyncHTTPrequest)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncHTTPRequest_Generic
+ Licensed under MIT license
+
+ Copyright (C) <2018>
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
+ as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+ Version: 1.0.1
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
+ *****************************************************************************************************************************/
+
+#pragma once
+
+#ifdef ASYNC_HTTP_DEBUG_PORT
+ #define A_DBG_PORT ASYNC_HTTP_DEBUG_PORT
+#else
+ #define A_DBG_PORT Serial
+#endif
+
+// Change _ASYNC_HTTP_LOGLEVEL_ to set tracing and logging verbosity
+// 0: DISABLED: no logging
+// 1: ERROR: errors
+// 2: WARN: errors and warnings
+// 3: INFO: errors, warnings and informational (default)
+// 4: DEBUG: errors, warnings, informational and debug
+
+#ifndef _ASYNC_HTTP_LOGLEVEL_
+ #define _ASYNC_HTTP_LOGLEVEL_ 0
+#endif
+
+#define AHTTP_LOGERROR(x) if(_ASYNC_HTTP_LOGLEVEL_>0) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.println(x); }
+#define AHTTP_LOGERROR0(x) if(_ASYNC_HTTP_LOGLEVEL_>0) { A_DBG_PORT.print(x); }
+#define AHTTP_LOGERROR1(x,y) if(_ASYNC_HTTP_LOGLEVEL_>0) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.println(y); }
+#define AHTTP_LOGERROR2(x,y,z) if(_ASYNC_HTTP_LOGLEVEL_>0) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.println(z); }
+#define AHTTP_LOGERROR3(x,y,z,w) if(_ASYNC_HTTP_LOGLEVEL_>0) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.print(z); A_DBG_PORT.print(" "); A_DBG_PORT.println(w); }
+
+#define AHTTP_LOGWARN(x) if(_ASYNC_HTTP_LOGLEVEL_>1) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.println(x); }
+#define AHTTP_LOGWARN0(x) if(_ASYNC_HTTP_LOGLEVEL_>1) { A_DBG_PORT.print(x); }
+#define AHTTP_LOGWARN1(x,y) if(_ASYNC_HTTP_LOGLEVEL_>1) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.println(y); }
+#define AHTTP_LOGWARN2(x,y,z) if(_ASYNC_HTTP_LOGLEVEL_>1) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.println(z); }
+#define AHTTP_LOGWARN3(x,y,z,w) if(_ASYNC_HTTP_LOGLEVEL_>1) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.print(z); A_DBG_PORT.print(" "); A_DBG_PORT.println(w); }
+
+#define AHTTP_LOGINFO(x) if(_ASYNC_HTTP_LOGLEVEL_>2) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.println(x); }
+#define AHTTP_LOGINFO0(x) if(_ASYNC_HTTP_LOGLEVEL_>2) { A_DBG_PORT.print(x); }
+#define AHTTP_LOGINFO1(x,y) if(_ASYNC_HTTP_LOGLEVEL_>2) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.println(y); }
+#define AHTTP_LOGINFO2(x,y,z) if(_ASYNC_HTTP_LOGLEVEL_>2) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.println(z); }
+#define AHTTP_LOGINFO3(x,y,z,w) if(_ASYNC_HTTP_LOGLEVEL_>2) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.print(z); A_DBG_PORT.print(" "); A_DBG_PORT.println(w); }
+
+#define AHTTP_LOGDEBUG(x) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.println(x); }
+#define AHTTP_LOGDEBUG0(x) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print(x); }
+#define AHTTP_LOGDEBUG1(x,y) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.println(y); }
+#define AHTTP_LOGDEBUG2(x,y,z) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.println(z); }
+#define AHTTP_LOGDEBUG3(x,y,z,w) if(_ASYNC_HTTP_LOGLEVEL_>3) { A_DBG_PORT.print("[AHTTP] "); A_DBG_PORT.print(x); A_DBG_PORT.print(" "); A_DBG_PORT.print(y); A_DBG_PORT.print(" "); A_DBG_PORT.print(z); A_DBG_PORT.print(" "); A_DBG_PORT.println(w); }
+
diff --git a/src_cpp/AsyncHTTPRequest_Generic.cpp b/src_cpp/AsyncHTTPRequest_Generic.cpp
new file mode 100644
index 0000000..532ec94
--- /dev/null
+++ b/src_cpp/AsyncHTTPRequest_Generic.cpp
@@ -0,0 +1,1192 @@
+/****************************************************************************************************************************
+ src_cpp/AsyncHTTPRequest_Generic.cpp - Dead simple AsyncHTTPRequest for ESP8266, ESP32 and currently STM32 with built-in LAN8742A Ethernet
+
+ For ESP8266, ESP32 and STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncHTTPRequest_STM32 is a library for the ESP8266, ESP32 and currently STM32 run built-in Ethernet WebServer
+
+ Based on and modified from asyncHTTPrequest Library (https://github.com/boblemaire/asyncHTTPrequest)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncHTTPRequest_Generic
+ Licensed under MIT license
+
+ Copyright (C) <2018>
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
+ as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+ Version: 1.0.1
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
+ *****************************************************************************************************************************/
+
+#include "AsyncHTTPRequest_Generic.h"
+
+
+//**************************************************************************************************************
+AsyncHTTPRequest::AsyncHTTPRequest(): _readyState(readyStateUnsent), _HTTPcode(0), _chunked(false), _debug(DEBUG_IOTA_HTTP_SET)
+ , _timeout(DEFAULT_RX_TIMEOUT), _lastActivity(0), _requestStartTime(0), _requestEndTime(0), _URL(nullptr)
+ , _connectedHost(nullptr), _connectedPort(-1), _client(nullptr), _contentLength(0), _contentRead(0)
+ , _readyStateChangeCB(nullptr), _readyStateChangeCBarg(nullptr), _onDataCB(nullptr), _onDataCBarg(nullptr)
+ , _request(nullptr), _response(nullptr), _chunks(nullptr), _headers(nullptr)
+{
+#ifdef ESP32
+ threadLock = xSemaphoreCreateRecursiveMutex();
+#endif
+}
+
+//**************************************************************************************************************
+AsyncHTTPRequest::~AsyncHTTPRequest()
+{
+ if (_client)
+ _client->close(true);
+
+ delete _URL;
+ delete _headers;
+ delete _request;
+ delete _response;
+ delete _chunks;
+ delete[] _connectedHost;
+
+#ifdef ESP32
+ vSemaphoreDelete(threadLock);
+#endif
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setDebug(bool debug)
+{
+ if (_debug || debug)
+ {
+ _debug = true;
+
+ AHTTP_LOGDEBUG3("setDebug(", debug ? "on" : "off", ") version", AsyncHTTPRequest_Generic_version);
+ }
+ _debug = debug;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::debug()
+{
+ return (_debug);
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::open(const char* method, const char* URL)
+{
+ AHTTP_LOGDEBUG3("open(", method, ", url =", URL);
+
+ if (_readyState != readyStateUnsent && _readyState != readyStateDone)
+ {
+ return false;
+ }
+
+ _requestStartTime = millis();
+
+ delete _URL;
+ delete _headers;
+ delete _request;
+ delete _response;
+ delete _chunks;
+
+ _URL = nullptr;
+ _headers = nullptr;
+ _response = nullptr;
+ _request = nullptr;
+ _chunks = nullptr;
+ _chunked = false;
+ _contentRead = 0;
+ _readyState = readyStateUnsent;
+
+ if (strcmp(method, "GET") == 0)
+ {
+ _HTTPmethod = HTTPmethodGET;
+ }
+ else if (strcmp(method, "POST") == 0)
+ {
+ _HTTPmethod = HTTPmethodPOST;
+ }
+ else
+ return false;
+
+ if (!_parseURL(URL))
+ {
+ return false;
+ }
+ if ( _client && _client->connected() && (strcmp(_URL->host, _connectedHost) != 0 || _URL->port != _connectedPort))
+ {
+ return false;
+ }
+
+ char* hostName = new char[strlen(_URL->host) + 10];
+ sprintf(hostName, "%s:%d", _URL->host, _URL->port);
+ _addHeader("host", hostName);
+ delete[] hostName;
+ _lastActivity = millis();
+
+ return _connect();
+}
+//**************************************************************************************************************
+void AsyncHTTPRequest::onReadyStateChange(readyStateChangeCB cb, void* arg)
+{
+ _readyStateChangeCB = cb;
+ _readyStateChangeCBarg = arg;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setTimeout(int seconds)
+{
+ AHTTP_LOGDEBUG1("setTimeout = ", seconds);
+
+ _timeout = seconds;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::send()
+{
+ AHTTP_LOGDEBUG("send()");
+
+ _lock;
+
+ if ( ! _buildRequest())
+ return false;
+
+ _send();
+ _unlock;
+
+ return true;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::send(String body)
+{
+ AHTTP_LOGDEBUG3("send(String)", body.substring(0, 16).c_str(), ", length =", body.length());
+
+ _lock;
+ _addHeader("Content-Length", String(body.length()).c_str());
+
+ if ( ! _buildRequest())
+ {
+ _unlock;
+ return false;
+ }
+
+ _request->write(body);
+ _send();
+ _unlock;
+
+ return true;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::send(const char* body)
+{
+ AHTTP_LOGDEBUG3("send(char)", body, ", length =", strlen(body));
+
+ _lock;
+ _addHeader("Content-Length", String(strlen(body)).c_str());
+
+ if ( ! _buildRequest())
+ {
+ _unlock;
+
+ return false;
+ }
+
+ _request->write(body);
+ _send();
+ _unlock;
+
+ return true;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::send(const uint8_t* body, size_t len)
+{
+ AHTTP_LOGDEBUG3("send(char)", (char*) body, ", length =", len);
+
+ _lock;
+ _addHeader("Content-Length", String(len).c_str());
+
+ if ( ! _buildRequest())
+ {
+ _unlock;
+
+ return false;
+ }
+
+ _request->write(body, len);
+ _send();
+ _unlock;
+
+ return true;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::send(xbuf* body, size_t len)
+{
+ AHTTP_LOGDEBUG3("send(char)", body->peekString(16).c_str(), ", length =", len);
+
+ _lock;
+ _addHeader("Content-Length", String(len).c_str());
+
+ if ( ! _buildRequest())
+ {
+ _unlock;
+
+ return false;
+ }
+
+ _request->write(body, len);
+ _send();
+ _unlock;
+
+ return true;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::abort()
+{
+ AHTTP_LOGDEBUG("abort()");
+
+ _lock;
+
+ if (! _client)
+ return;
+
+ _client->abort();
+ _unlock;
+}
+//**************************************************************************************************************
+reqStates AsyncHTTPRequest::readyState()
+{
+ return _readyState;
+}
+
+//**************************************************************************************************************
+int AsyncHTTPRequest::responseHTTPcode()
+{
+ return _HTTPcode;
+}
+
+//**************************************************************************************************************
+String AsyncHTTPRequest::responseText()
+{
+ AHTTP_LOGDEBUG("responseText()");
+
+ _lock;
+
+ if ( ! _response || _readyState < readyStateLoading || ! available())
+ {
+ AHTTP_LOGDEBUG("responseText() no data");
+
+ _unlock;
+
+ return String();
+ }
+
+ String localString;
+ size_t avail = available();
+
+ if ( ! localString.reserve(avail))
+ {
+ AHTTP_LOGDEBUG("responseText() no buffer");
+
+ _HTTPcode = HTTPCODE_TOO_LESS_RAM;
+ _client->abort();
+ _unlock;
+
+ return String();
+ }
+
+ localString = _response->readString(avail);
+ _contentRead += localString.length();
+
+ AHTTP_LOGDEBUG3("responseText(char)", localString.substring(0, 16).c_str(), ", avail =", avail);
+
+ _unlock;
+
+ return localString;
+}
+
+//**************************************************************************************************************
+size_t AsyncHTTPRequest::responseRead(uint8_t* buf, size_t len)
+{
+ if ( ! _response || _readyState < readyStateLoading || ! available())
+ {
+ //DEBUG_HTTP("responseRead() no data\r\n");
+ AHTTP_LOGDEBUG("responseRead() no data");
+
+ return 0;
+ }
+
+ _lock;
+ size_t avail = available() > len ? len : available();
+ _response->read(buf, avail);
+
+ AHTTP_LOGDEBUG3("responseRead(char)", (char*) buf, ", avail =", avail);
+
+ _contentRead += avail;
+ _unlock;
+
+ return avail;
+}
+
+//**************************************************************************************************************
+size_t AsyncHTTPRequest::available()
+{
+ if (_readyState < readyStateLoading)
+ return 0;
+
+ if (_chunked && (_contentLength - _contentRead) < _response->available())
+ {
+ return _contentLength - _contentRead;
+ }
+
+ return _response->available();
+}
+
+//**************************************************************************************************************
+size_t AsyncHTTPRequest::responseLength()
+{
+ if (_readyState < readyStateLoading)
+ return 0;
+
+ return _contentLength;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::onData(onDataCB cb, void* arg)
+{
+ AHTTP_LOGDEBUG("onData() CB set");
+
+ _onDataCB = cb;
+ _onDataCBarg = arg;
+}
+
+//**************************************************************************************************************
+uint32_t AsyncHTTPRequest::elapsedTime()
+{
+ if (_readyState <= readyStateOpened)
+ return 0;
+
+ if (_readyState != readyStateDone)
+ {
+ return millis() - _requestStartTime;
+ }
+
+ return _requestEndTime - _requestStartTime;
+}
+
+//**************************************************************************************************************
+String AsyncHTTPRequest::version()
+{
+ return String(AsyncHTTPRequest_Generic_version);
+}
+
+/*______________________________________________________________________________________________________________
+
+ PPPP RRRR OOO TTTTT EEEEE CCC TTTTT EEEEE DDDD
+ P P R R O O T E C C T E D D
+ PPPP RRRR O O T EEE C T EEE D D
+ P R R O O T E C C T E D D
+ P R R OOO T EEEEE CCC T EEEEE DDDD
+ _______________________________________________________________________________________________________________*/
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::_parseURL(const char* url)
+{
+ return _parseURL(String(url));
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::_parseURL(String url)
+{
+ delete _URL;
+
+ int hostBeg = 0;
+ _URL = new URL;
+ _URL->scheme = new char[8];
+ strcpy(_URL->scheme, "HTTP://");
+
+ if (url.substring(0, 7).equalsIgnoreCase("HTTP://"))
+ {
+ hostBeg += 7;
+ }
+ else if (url.substring(0, 8).equalsIgnoreCase("HTTPS://"))
+ {
+ return false;
+ }
+
+ int pathBeg = url.indexOf('/', hostBeg);
+
+ if (pathBeg < 0)
+ return false;
+
+ int hostEnd = pathBeg;
+ int portBeg = url.indexOf(':', hostBeg);
+
+ if (portBeg > 0 && portBeg < pathBeg)
+ {
+ _URL->port = url.substring(portBeg + 1, pathBeg).toInt();
+ hostEnd = portBeg;
+ }
+
+ _URL->host = new char[hostEnd - hostBeg + 1];
+ strcpy(_URL->host, url.substring(hostBeg, hostEnd).c_str());
+
+ int queryBeg = url.indexOf('?');
+
+ if (queryBeg < 0)
+ queryBeg = url.length();
+
+ _URL->path = new char[queryBeg - pathBeg + 1];
+ strcpy(_URL->path, url.substring(pathBeg, queryBeg).c_str());
+ _URL->query = new char[url.length() - queryBeg + 1];
+ strcpy(_URL->query, url.substring(queryBeg).c_str());
+
+ AHTTP_LOGDEBUG2("_parseURL(): scheme+host", _URL->scheme, _URL->host);
+ AHTTP_LOGDEBUG3("_parseURL(): port+path+query", _URL->port, _URL->path, _URL->query);
+
+ return true;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::_connect()
+{
+ AHTTP_LOGDEBUG("_connect()");
+
+ if ( ! _client)
+ {
+ _client = new AsyncClient();
+ }
+
+ delete[] _connectedHost;
+
+ _connectedHost = new char[strlen(_URL->host) + 1];
+ strcpy(_connectedHost, _URL->host);
+ _connectedPort = _URL->port;
+
+ _client->onConnect([](void *obj, AsyncClient * client)
+ {
+ ((AsyncHTTPRequest*)(obj))->_onConnect(client);
+ }, this);
+
+ _client->onDisconnect([](void *obj, AsyncClient * client)
+ {
+ ((AsyncHTTPRequest*)(obj))->_onDisconnect(client);
+ }, this);
+
+ _client->onPoll([](void *obj, AsyncClient * client)
+ {
+ ((AsyncHTTPRequest*)(obj))->_onPoll(client);
+ }, this);
+
+ _client->onError([](void *obj, AsyncClient * client, uint32_t error)
+ {
+ ((AsyncHTTPRequest*)(obj))->_onError(client, error);
+ }, this);
+
+ if ( ! _client->connected())
+ {
+ if ( ! _client->connect(_URL->host, _URL->port))
+ {
+ AHTTP_LOGDEBUG3("client.connect failed:", _URL->host, ",", _URL->port);
+
+ _HTTPcode = HTTPCODE_NOT_CONNECTED;
+ _setReadyState(readyStateDone);
+
+ return false;
+ }
+ }
+ else
+ {
+ _onConnect(_client);
+ }
+
+ _lastActivity = millis();
+
+ return true;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::_buildRequest()
+{
+ AHTTP_LOGDEBUG("_buildRequest()");
+
+ // Build the header.
+ if ( ! _request)
+ _request = new xbuf;
+
+ _request->write(_HTTPmethod == HTTPmethodGET ? "GET " : "POST ");
+ _request->write(_URL->path);
+ _request->write(_URL->query);
+ _request->write(" HTTP/1.1\r\n");
+
+ AHTTP_LOGDEBUG3(_HTTPmethod == HTTPmethodGET ? "GET " : "POST ", _URL->path, _URL->query, " HTTP/1.1\r\n" );
+
+ delete _URL;
+
+ _URL = nullptr;
+ header* hdr = _headers;
+
+ while (hdr)
+ {
+ _request->write(hdr->name);
+ _request->write(':');
+ _request->write(hdr->value);
+ _request->write("\r\n");
+
+ AHTTP_LOGDEBUG3(hdr->name, ":", hdr->value, "\r\n" );
+
+ hdr = hdr->next;
+ }
+
+ delete _headers;
+ _headers = nullptr;
+ _request->write("\r\n");
+
+ return true;
+}
+
+//**************************************************************************************************************
+size_t AsyncHTTPRequest::_send()
+{
+ if ( ! _request)
+ return 0;
+
+ AHTTP_LOGDEBUG1("_send(), _request->available =", _request->available());
+
+ if ( ! _client->connected() || ! _client->canSend())
+ {
+ AHTTP_LOGDEBUG("*can't send");
+
+ return 0;
+ }
+
+ size_t supply = _request->available();
+ size_t demand = _client->space();
+
+ if (supply > demand)
+ supply = demand;
+
+ size_t sent = 0;
+ uint8_t* temp = new uint8_t[100];
+
+ while (supply)
+ {
+ size_t chunk = supply < 100 ? supply : 100;
+ supply -= _request->read(temp, chunk);
+ sent += _client->add((char*)temp, chunk);
+ }
+
+ delete temp;
+
+ if (_request->available() == 0)
+ {
+ delete _request;
+ _request = nullptr;
+ }
+
+ _client->send();
+
+ AHTTP_LOGDEBUG1("*send", sent);
+
+ _lastActivity = millis();
+
+ return sent;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_setReadyState(reqStates newState)
+{
+ if (_readyState != newState)
+ {
+ _readyState = newState;
+
+ AHTTP_LOGDEBUG1("_setReadyState :", _readyState);
+
+ if (_readyStateChangeCB)
+ {
+ _readyStateChangeCB(_readyStateChangeCBarg, this, _readyState);
+ }
+ }
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_processChunks()
+{
+ while (_chunks->available())
+ {
+ AHTTP_LOGDEBUG3("_processChunks()", _chunks->peekString(16).c_str(), ", chunks available =", _chunks->available());
+
+ size_t _chunkRemaining = _contentLength - _contentRead - _response->available();
+ _chunkRemaining -= _response->write(_chunks, _chunkRemaining);
+
+ if (_chunks->indexOf("\r\n") == -1)
+ {
+ return;
+ }
+
+ String chunkHeader = _chunks->readStringUntil("\r\n");
+
+ AHTTP_LOGDEBUG3("*getChunkHeader", chunkHeader.c_str(), ", chunkHeader length =", chunkHeader.length());
+
+ size_t chunkLength = strtol(chunkHeader.c_str(), nullptr, 16);
+ _contentLength += chunkLength;
+
+ if (chunkLength == 0)
+ {
+ char* connectionHdr = respHeaderValue("connection");
+
+ if (connectionHdr && (strcasecmp_P(connectionHdr, PSTR("disconnect")) == 0))
+ {
+ AHTTP_LOGDEBUG("*all chunks received - closing TCP");
+
+ _client->close();
+ }
+ else
+ {
+ AHTTP_LOGDEBUG("*all chunks received - no disconnect");
+ }
+
+ _requestEndTime = millis();
+ _lastActivity = 0;
+ _timeout = 0;
+ _setReadyState(readyStateDone);
+
+ return;
+ }
+ }
+}
+
+/*______________________________________________________________________________________________________________
+
+ EEEEE V V EEEEE N N TTTTT H H AAA N N DDDD L EEEEE RRRR SSS
+ E V V E NN N T H H A A NN N D D L E R R S
+ EEE V V EEE N N N T HHHHH AAAAA N N N D D L EEE RRRR SSS
+ E V V E N NN T H H A A N NN D D L E R R S
+ EEEEE V EEEEE N N T H H A A N N DDDD LLLLL EEEEE R R SSS
+ _______________________________________________________________________________________________________________*/
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_onConnect(AsyncClient* client)
+{
+ AHTTP_LOGDEBUG("_onConnect handler");
+
+ _lock;
+ _client = client;
+ _setReadyState(readyStateOpened);
+ _response = new xbuf;
+ _contentLength = 0;
+ _contentRead = 0;
+ _chunked = false;
+
+ _client->onAck([](void* obj, AsyncClient * client, size_t len, uint32_t time)
+ {
+ ((AsyncHTTPRequest*)(obj))->_send();
+ }, this);
+
+ _client->onData([](void* obj, AsyncClient * client, void* data, size_t len)
+ {
+ ((AsyncHTTPRequest*)(obj))->_onData(data, len);
+ }, this);
+
+ if (_client->canSend())
+ {
+ _send();
+ }
+
+ _lastActivity = millis();
+ _unlock;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_onPoll(AsyncClient* client)
+{
+ _lock;
+
+ if (_timeout && (millis() - _lastActivity) > (_timeout * 1000))
+ {
+ _client->close();
+ _HTTPcode = HTTPCODE_TIMEOUT;
+
+ AHTTP_LOGDEBUG("_onPoll timeout");
+ }
+
+ if (_onDataCB && available())
+ {
+ _onDataCB(_onDataCBarg, this, available());
+ }
+
+ _unlock;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_onError(AsyncClient* client, int8_t error)
+{
+ AHTTP_LOGDEBUG1("_onError handler error =", error);
+
+ _HTTPcode = error;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_onDisconnect(AsyncClient* client)
+{
+ AHTTP_LOGDEBUG("\n_onDisconnect handler");
+
+ _lock;
+
+ if (_readyState < readyStateOpened)
+ {
+ _HTTPcode = HTTPCODE_NOT_CONNECTED;
+ }
+ else if (_HTTPcode > 0 &&
+ (_readyState < readyStateHdrsRecvd || (_contentRead + _response->available()) < _contentLength))
+ {
+ _HTTPcode = HTTPCODE_CONNECTION_LOST;
+ }
+
+ delete _client;
+ _client = nullptr;
+
+ delete[] _connectedHost;
+ _connectedHost = nullptr;
+
+ _connectedPort = -1;
+ _requestEndTime = millis();
+ _lastActivity = 0;
+ _setReadyState(readyStateDone);
+ _unlock;
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::_onData(void* Vbuf, size_t len)
+{
+ AHTTP_LOGDEBUG3("_onData handler", (char*) Vbuf, ", len =", len);
+
+ _lastActivity = millis();
+
+ // Transfer data to xbuf
+ if (_chunks)
+ {
+ _chunks->write((uint8_t*)Vbuf, len);
+ _processChunks();
+ }
+ else
+ {
+ _response->write((uint8_t*)Vbuf, len);
+ }
+
+ // if headers not complete, collect them. If still not complete, just return.
+ if (_readyState == readyStateOpened)
+ {
+ if ( ! _collectHeaders())
+ return;
+ }
+
+ // If there's data in the buffer and not Done, advance readyState to Loading.
+ if (_response->available() && _readyState != readyStateDone)
+ {
+ _setReadyState(readyStateLoading);
+ }
+
+ // If not chunked and all data read, close it up.
+ if ( ! _chunked && (_response->available() + _contentRead) >= _contentLength)
+ {
+ char* connectionHdr = respHeaderValue("connection");
+
+ if (connectionHdr && (strcasecmp_P(connectionHdr, PSTR("disconnect")) == 0))
+ {
+ AHTTP_LOGDEBUG("*all data received - closing TCP");
+
+ _client->close();
+ }
+ else
+ {
+ AHTTP_LOGDEBUG("*all data received - no disconnect");
+ }
+
+ _requestEndTime = millis();
+ _lastActivity = 0;
+ _timeout = 0;
+ _setReadyState(readyStateDone);
+ }
+
+ // If onData callback requested, do so.
+ if (_onDataCB && available())
+ {
+ _onDataCB(_onDataCBarg, this, available());
+ }
+
+ _unlock;
+
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::_collectHeaders()
+{
+ AHTTP_LOGDEBUG("_collectHeaders()");
+
+ // Loop to parse off each header line. Drop out and return false if no \r\n (incomplete)
+ do
+ {
+ String headerLine = _response->readStringUntil("\r\n");
+
+ // If no line, return false.
+ if ( ! headerLine.length())
+ {
+ return false;
+ }
+
+ // If empty line, all headers are in, advance readyState.
+ if (headerLine.length() == 2)
+ {
+ _setReadyState(readyStateHdrsRecvd);
+ }
+ // If line is HTTP header, capture HTTPcode.
+ else if (headerLine.substring(0, 7) == "HTTP/1.")
+ {
+ _HTTPcode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
+ }
+ // Ordinary header, add to header list.
+ else
+ {
+ int colon = headerLine.indexOf(':');
+
+ if (colon != -1)
+ {
+ String name = headerLine.substring(0, colon);
+ name.trim();
+ String value = headerLine.substring(colon + 1);
+ value.trim();
+ _addHeader(name.c_str(), value.c_str());
+ }
+ }
+ } while (_readyState == readyStateOpened);
+
+ // If content-Length header, set _contentLength
+ header *hdr = _getHeader("Content-Length");
+
+ if (hdr)
+ {
+ _contentLength = strtol(hdr->value, nullptr, 10);
+ }
+
+ // If chunked specified, try to set _contentLength to size of first chunk
+ hdr = _getHeader("Transfer-Encoding");
+
+ if (hdr && strcasecmp_P(hdr->value, PSTR("chunked")) == 0)
+ {
+ AHTTP_LOGDEBUG("*transfer-encoding: chunked");
+
+ _chunked = true;
+ _contentLength = 0;
+ _chunks = new xbuf;
+ _chunks->write(_response, _response->available());
+ _processChunks();
+ }
+
+ return true;
+}
+
+
+/*_____________________________________________________________________________________________________________
+
+ H H EEEEE AAA DDDD EEEEE RRRR SSS
+ H H E A A D D E R R S
+ HHHHH EEE AAAAA D D EEE RRRR SSS
+ H H E A A D D E R R S
+ H H EEEEE A A DDDD EEEEE R R SSS
+ ______________________________________________________________________________________________________________*/
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setReqHeader(const char* name, const char* value)
+{
+ if (_readyState <= readyStateOpened && _headers)
+ {
+ _addHeader(name, value);
+ }
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setReqHeader(const char* name, int32_t value)
+{
+ if (_readyState <= readyStateOpened && _headers)
+ {
+ setReqHeader(name, String(value).c_str());
+ }
+}
+
+#if (ESP32 || ESP8266)
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setReqHeader(const char* name, const __FlashStringHelper* value)
+{
+ if (_readyState <= readyStateOpened && _headers)
+ {
+ char* _value = _charstar(value);
+ _addHeader(name, _value);
+ delete[] _value;
+ }
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setReqHeader(const __FlashStringHelper *name, const char* value)
+{
+ if (_readyState <= readyStateOpened && _headers)
+ {
+ char* _name = _charstar(name);
+ _addHeader(_name, value);
+ delete[] _name;
+ }
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setReqHeader(const __FlashStringHelper *name, const __FlashStringHelper* value)
+{
+ if (_readyState <= readyStateOpened && _headers)
+ {
+ char* _name = _charstar(name);
+ char* _value = _charstar(value);
+ _addHeader(_name, _value);
+ delete[] _name;
+ delete[] _value;
+ }
+}
+
+//**************************************************************************************************************
+void AsyncHTTPRequest::setReqHeader(const __FlashStringHelper *name, int32_t value)
+{
+ if (_readyState <= readyStateOpened && _headers)
+ {
+ char* _name = _charstar(name);
+ setReqHeader(_name, String(value).c_str());
+ delete[] _name;
+ }
+}
+
+#endif
+
+//**************************************************************************************************************
+int AsyncHTTPRequest::respHeaderCount()
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return 0;
+
+ int count = 0;
+ header* hdr = _headers;
+
+ while (hdr)
+ {
+ count++;
+ hdr = hdr->next;
+ }
+
+ return count;
+}
+
+//**************************************************************************************************************
+char* AsyncHTTPRequest::respHeaderName(int ndx)
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return nullptr;
+
+ header* hdr = _getHeader(ndx);
+
+ if ( ! hdr)
+ return nullptr;
+
+ return hdr->name;
+}
+
+//**************************************************************************************************************
+char* AsyncHTTPRequest::respHeaderValue(const char* name)
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return nullptr;
+
+ header* hdr = _getHeader(name);
+
+ if ( ! hdr)
+ return nullptr;
+
+ return hdr->value;
+}
+
+//**************************************************************************************************************
+char* AsyncHTTPRequest::respHeaderValue(int ndx)
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return nullptr;
+
+ header* hdr = _getHeader(ndx);
+
+ if ( ! hdr)
+ return nullptr;
+
+ return hdr->value;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::respHeaderExists(const char* name)
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return false;
+
+ header* hdr = _getHeader(name);
+
+ if ( ! hdr)
+ return false;
+
+ return true;
+}
+
+
+#if (ESP32 || ESP8266)
+
+//**************************************************************************************************************
+char* AsyncHTTPRequest::respHeaderValue(const __FlashStringHelper *name)
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return nullptr;
+
+ char* _name = _charstar(name);
+ header* hdr = _getHeader(_name);
+ delete[] _name;
+
+ if ( ! hdr)
+ return nullptr;
+
+ return hdr->value;
+}
+
+//**************************************************************************************************************
+bool AsyncHTTPRequest::respHeaderExists(const __FlashStringHelper *name)
+{
+ if (_readyState < readyStateHdrsRecvd)
+ return false;
+
+ char* _name = _charstar(name);
+ header* hdr = _getHeader(_name);
+ delete[] _name;
+
+ if ( ! hdr)
+ return false;
+
+ return true;
+}
+
+#endif
+
+//**************************************************************************************************************
+String AsyncHTTPRequest::headers()
+{
+ _lock;
+ String _response = "";
+ header* hdr = _headers;
+
+ while (hdr)
+ {
+ _response += hdr->name;
+ _response += ':';
+ _response += hdr->value;
+ _response += "\r\n";
+ hdr = hdr->next;
+ }
+
+ _response += "\r\n";
+ _unlock;
+
+ return _response;
+}
+
+//**************************************************************************************************************
+AsyncHTTPRequest::header* AsyncHTTPRequest::_addHeader(const char* name, const char* value)
+{
+ _lock;
+ header* hdr = (header*) &_headers;
+
+ while (hdr->next)
+ {
+ if (strcasecmp(name, hdr->next->name) == 0)
+ {
+ header* oldHdr = hdr->next;
+ hdr->next = hdr->next->next;
+ oldHdr->next = nullptr;
+ delete oldHdr;
+ }
+ else
+ {
+ hdr = hdr->next;
+ }
+ }
+
+ hdr->next = new header;
+ hdr->next->name = new char[strlen(name) + 1];
+ strcpy(hdr->next->name, name);
+ hdr->next->value = new char[strlen(value) + 1];
+ strcpy(hdr->next->value, value);
+ _unlock;
+
+ return hdr->next;
+}
+
+//**************************************************************************************************************
+AsyncHTTPRequest::header* AsyncHTTPRequest::_getHeader(const char* name)
+{
+ _lock;
+ header* hdr = _headers;
+
+ while (hdr)
+ {
+ if (strcasecmp(name, hdr->name) == 0)
+ break;
+
+ hdr = hdr->next;
+ }
+
+ _unlock;
+
+ return hdr;
+}
+
+//**************************************************************************************************************
+AsyncHTTPRequest::header* AsyncHTTPRequest::_getHeader(int ndx)
+{
+ _lock;
+ header* hdr = _headers;
+
+ while (hdr)
+ {
+ if ( ! ndx--)
+ break;
+
+ hdr = hdr->next;
+ }
+
+ _unlock;
+
+ return hdr;
+}
+
+#if (ESP32 || ESP8266)
+
+//**************************************************************************************************************
+char* AsyncHTTPRequest::_charstar(const __FlashStringHelper * str)
+{
+ if ( ! str)
+ return nullptr;
+
+ char* ptr = new char[strlen_P((PGM_P)str) + 1];
+ strcpy_P(ptr, (PGM_P)str);
+
+ return ptr;
+}
+
+#endif
diff --git a/src_cpp/AsyncHTTPRequest_Generic.h b/src_cpp/AsyncHTTPRequest_Generic.h
new file mode 100644
index 0000000..7d6f54d
--- /dev/null
+++ b/src_cpp/AsyncHTTPRequest_Generic.h
@@ -0,0 +1,265 @@
+/****************************************************************************************************************************
+ src_cpp/AsyncHTTPRequest_Generic.h - Dead simple AsyncHTTPRequest for ESP8266, ESP32 and currently STM32 with built-in LAN8742A Ethernet
+
+ For ESP8266, ESP32 and STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncHTTPRequest_STM32 is a library for the ESP8266, ESP32 and currently STM32 run built-in Ethernet WebServer
+
+ Based on and modified from asyncHTTPrequest Library (https://github.com/boblemaire/asyncHTTPrequest)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncHTTPRequest_Generic
+ Licensed under MIT license
+
+ Copyright (C) <2018>
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
+ as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+ Version: 1.0.1
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
+ *****************************************************************************************************************************/
+
+#pragma once
+
+#define AsyncHTTPRequest_Generic_version "1.0.0"
+
+#include
+
+#include "AsyncHTTPRequest_Debug_Generic.h"
+
+#ifndef DEBUG_IOTA_PORT
+ #define DEBUG_IOTA_PORT Serial
+#endif
+
+#ifdef DEBUG_IOTA_HTTP
+ #define DEBUG_IOTA_HTTP_SET true
+#else
+ #define DEBUG_IOTA_HTTP_SET false
+#endif
+
+#if ESP32
+
+ #include
+ #define _lock xSemaphoreTakeRecursive(threadLock,portMAX_DELAY)
+ #define _unlock xSemaphoreGiveRecursive(threadLock)
+
+#elif ESP8266
+
+ #include
+ #define _lock
+ #define _unlock
+
+#elif ( defined(STM32F0) || defined(STM32F1) || defined(STM32F2) || defined(STM32F3) ||defined(STM32F4) || defined(STM32F7) || \
+ defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32H7) ||defined(STM32G0) || defined(STM32G4) || \
+ defined(STM32WB) || defined(STM32MP1) )
+
+ #include "STM32AsyncTCP.h"
+ #define _lock
+ #define _unlock
+
+#endif
+
+#include
+#include
+
+#define DEBUG_HTTP(format,...) if(_debug){\
+ DEBUG_IOTA_PORT.printf("Debug(%3ld): ", millis()-_requestStartTime);\
+ DEBUG_IOTA_PORT.printf_P(PSTR(format),##__VA_ARGS__);}
+
+#define DEFAULT_RX_TIMEOUT 3 // Seconds for timeout
+
+#define HTTPCODE_CONNECTION_REFUSED (-1)
+#define HTTPCODE_SEND_HEADER_FAILED (-2)
+#define HTTPCODE_SEND_PAYLOAD_FAILED (-3)
+#define HTTPCODE_NOT_CONNECTED (-4)
+#define HTTPCODE_CONNECTION_LOST (-5)
+#define HTTPCODE_NO_STREAM (-6)
+#define HTTPCODE_NO_HTTP_SERVER (-7)
+#define HTTPCODE_TOO_LESS_RAM (-8)
+#define HTTPCODE_ENCODING (-9)
+#define HTTPCODE_STREAM_WRITE (-10)
+#define HTTPCODE_TIMEOUT (-11)
+
+typedef enum
+{
+ readyStateUnsent = 0, // Client created, open not yet called
+ readyStateOpened = 1, // open() has been called, connected
+ readyStateHdrsRecvd = 2, // send() called, response headers available
+ readyStateLoading = 3, // receiving, partial data available
+ readyStateDone = 4 // Request complete, all data available.
+} reqStates;
+
+class AsyncHTTPRequest
+{
+ struct header
+ {
+ header* next;
+ char* name;
+ char* value;
+
+ header(): next(nullptr), name(nullptr), value(nullptr)
+ {};
+
+ ~header()
+ {
+ delete[] name;
+ delete[] value;
+ delete next;
+ }
+ };
+
+ struct URL
+ {
+ char* scheme;
+ char* user;
+ char* pwd;
+ char* host;
+ int port;
+ char* path;
+ char* query;
+ char* fragment;
+
+ URL(): scheme(nullptr), user(nullptr), pwd(nullptr), host(nullptr),
+ port(80), path(nullptr), query(nullptr), fragment(nullptr)
+ {};
+
+ ~URL()
+ {
+ delete[] scheme;
+ delete[] user;
+ delete[] pwd;
+ delete[] host;
+ delete[] path;
+ delete[] query;
+ delete[] fragment;
+ }
+ };
+
+ typedef std::function readyStateChangeCB;
+ typedef std::function onDataCB;
+
+ public:
+ AsyncHTTPRequest();
+ ~AsyncHTTPRequest();
+
+
+ //External functions in typical order of use:
+ //__________________________________________________________________________________________________________*/
+ void setDebug(bool); // Turn debug message on/off
+ bool debug(); // is debug on or off?
+
+ bool open(const char* /*GET/POST*/, const char* URL); // Initiate a request
+ void onReadyStateChange(readyStateChangeCB, void* arg = 0); // Optional event handler for ready state change
+ // or you can simply poll readyState()
+ void setTimeout(int); // overide default timeout (seconds)
+
+ void setReqHeader(const char* name, const char* value); // add a request header
+ void setReqHeader(const char* name, int32_t value); // overload to use integer value
+
+#if (ESP32 || ESP8266)
+ void setReqHeader(const char* name, const __FlashStringHelper* value);
+ void setReqHeader(const __FlashStringHelper *name, const char* value);
+ void setReqHeader(const __FlashStringHelper *name, const __FlashStringHelper* value);
+ void setReqHeader(const __FlashStringHelper *name, int32_t value);
+#endif
+
+ bool send(); // Send the request (GET)
+ bool send(String body); // Send the request (POST)
+ bool send(const char* body); // Send the request (POST)
+ bool send(const uint8_t* buffer, size_t len); // Send the request (POST) (binary data?)
+ bool send(xbuf* body, size_t len); // Send the request (POST) data in an xbuf
+ void abort(); // Abort the current operation
+
+ reqStates readyState(); // Return the ready state
+
+ int respHeaderCount(); // Retrieve count of response headers
+ char* respHeaderName(int index); // Return header name by index
+ char* respHeaderValue(int index); // Return header value by index
+ char* respHeaderValue(const char* name); // Return header value by name
+
+ bool respHeaderExists(const char* name); // Does header exist by name?
+
+#if (ESP32 || ESP8266)
+ char* respHeaderValue(const __FlashStringHelper *name);
+ bool respHeaderExists(const __FlashStringHelper *name);
+#endif
+
+ String headers(); // Return all headers as String
+
+ void onData(onDataCB, void* arg = 0); // Notify when min data is available
+ size_t available(); // response available
+ size_t responseLength(); // indicated response length or sum of chunks to date
+ int responseHTTPcode(); // HTTP response code or (negative) error code
+ String responseText(); // response (whole* or partial* as string)
+ size_t responseRead(uint8_t* buffer, size_t len); // Read response into buffer
+ uint32_t elapsedTime(); // Elapsed time of in progress transaction or last completed (ms)
+ String version(); // Version of AsyncHTTPRequest
+ //___________________________________________________________________________________________________________________________________
+
+ private:
+
+ enum {HTTPmethodGET, HTTPmethodPOST} _HTTPmethod;
+
+ reqStates _readyState;
+
+ int16_t _HTTPcode; // HTTP response code or (negative) exception code
+ bool _chunked; // Processing chunked response
+ bool _debug; // Debug state
+ uint32_t _timeout; // Default or user overide RxTimeout in seconds
+ uint32_t _lastActivity; // Time of last activity
+ uint32_t _requestStartTime; // Time last open() issued
+ uint32_t _requestEndTime; // Time of last disconnect
+ URL* _URL; // -> URL data structure
+ char* _connectedHost; // Host when connected
+ int _connectedPort; // Port when connected
+ AsyncClient* _client; // ESPAsyncTCP AsyncClient instance
+ size_t _contentLength; // content-length header value or sum of chunk headers
+ size_t _contentRead; // number of bytes retrieved by user since last open()
+ readyStateChangeCB _readyStateChangeCB; // optional callback for readyState change
+ void* _readyStateChangeCBarg; // associated user argument
+ onDataCB _onDataCB; // optional callback when data received
+ void* _onDataCBarg; // associated user argument
+
+#ifdef ESP32
+ SemaphoreHandle_t threadLock;
+#endif
+
+ // request and response String buffers and header list (same queue for request and response).
+
+ xbuf* _request; // Tx data buffer
+ xbuf* _response; // Rx data buffer for headers
+ xbuf* _chunks; // First stage for chunked response
+ header* _headers; // request or (readyState > readyStateHdrsRcvd) response headers
+
+ // Protected functions
+
+ header* _addHeader(const char*, const char*);
+ header* _getHeader(const char*);
+ header* _getHeader(int);
+ bool _buildRequest();
+ bool _parseURL(const char*);
+ bool _parseURL(String);
+ void _processChunks();
+ bool _connect();
+ size_t _send();
+ void _setReadyState(reqStates);
+
+#if (ESP32 || ESP8266)
+ char* _charstar(const __FlashStringHelper *str);
+#endif
+
+ // callbacks
+
+ void _onConnect(AsyncClient*);
+ void _onDisconnect(AsyncClient*);
+ void _onData(void*, size_t);
+ void _onError(AsyncClient*, int8_t);
+ void _onPoll(AsyncClient*);
+ bool _collectHeaders();
+};
diff --git a/src_cpp/utility/xbuf.cpp b/src_cpp/utility/xbuf.cpp
new file mode 100644
index 0000000..108283e
--- /dev/null
+++ b/src_cpp/utility/xbuf.cpp
@@ -0,0 +1,392 @@
+/****************************************************************************************************************************
+ src_cpp/utility/xbuf_Impl.h - Dead simple AsyncHTTPRequest for ESP8266, ESP32 and currently STM32 with built-in LAN8742A Ethernet
+
+ For ESP8266, ESP32 and STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncHTTPRequest_STM32 is a library for the ESP8266, ESP32 and currently STM32 run built-in Ethernet WebServer
+
+ Based on and modified from asyncHTTPrequest Library (https://github.com/boblemaire/asyncHTTPrequest)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncHTTPRequest_Generic
+ Licensed under MIT license
+
+ Copyright (C) <2018>
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
+ as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+ Version: 1.0.1
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
+ *****************************************************************************************************************************/
+
+#include "utility/xbuf.h"
+
+xbuf::xbuf(const uint16_t segSize) : _head(nullptr), _tail(nullptr), _used(0), _free(0), _offset(0)
+{
+ _segSize = (segSize + 3) & -4;//((segSize + 3) >> 2) << 2;
+}
+
+//*******************************************************************************************************************
+xbuf::~xbuf()
+{
+ flush();
+}
+
+//*******************************************************************************************************************
+size_t xbuf::write(const uint8_t byte)
+{
+ return write((uint8_t*) &byte, 1);
+}
+
+//*******************************************************************************************************************
+size_t xbuf::write(const char* buf)
+{
+ return write((uint8_t*)buf, strlen(buf));
+}
+
+//*******************************************************************************************************************
+size_t xbuf::write(String string)
+{
+ return write((uint8_t*)string.c_str(), string.length());
+}
+
+//*******************************************************************************************************************
+size_t xbuf::write(const uint8_t* buf, const size_t len)
+{
+ size_t supply = len;
+
+ while (supply)
+ {
+ if (!_free)
+ {
+ addSeg();
+ }
+
+ size_t demand = _free < supply ? _free : supply;
+ memcpy(_tail->data + ((_offset + _used) % _segSize), buf + (len - supply), demand);
+ _free -= demand;
+ _used += demand;
+ supply -= demand;
+ }
+
+ return len;
+}
+
+//*******************************************************************************************************************
+size_t xbuf::write(xbuf* buf, const size_t len)
+{
+ size_t supply = len;
+
+ if (supply > buf->available())
+ {
+ supply = buf->available();
+ }
+
+ size_t read = 0;
+
+ while (supply)
+ {
+ if (!_free)
+ {
+ addSeg();
+ }
+
+ size_t demand = _free < supply ? _free : supply;
+ read += buf->read(_tail->data + ((_offset + _used) % _segSize), demand);
+ _free -= demand;
+ _used += demand;
+ supply -= demand;
+ }
+
+ return read;
+}
+
+//*******************************************************************************************************************
+uint8_t xbuf::read()
+{
+ uint8_t byte = 0;
+ read((uint8_t*) &byte, 1);
+
+ return byte;
+}
+
+//*******************************************************************************************************************
+uint8_t xbuf::peek()
+{
+ uint8_t byte = 0;
+ peek((uint8_t*) &byte, 1);
+
+ return byte;
+}
+
+//*******************************************************************************************************************
+size_t xbuf::read(uint8_t* buf, const size_t len)
+{
+ size_t read = 0;
+
+ while (read < len && _used)
+ {
+ size_t supply = (_offset + _used) > _segSize ? _segSize - _offset : _used;
+ size_t demand = len - read;
+ size_t chunk = supply < demand ? supply : demand;
+ memcpy(buf + read, _head->data + _offset, chunk);
+ _offset += chunk;
+ _used -= chunk;
+ read += chunk;
+
+ if (_offset == _segSize)
+ {
+ remSeg();
+ _offset = 0;
+ }
+ }
+
+ if ( ! _used)
+ {
+ flush();
+ }
+
+ return read;
+}
+
+//*******************************************************************************************************************
+size_t xbuf::peek(uint8_t* buf, const size_t len)
+{
+ size_t read = 0;
+ xseg* seg = _head;
+ size_t offset = _offset;
+ size_t used = _used;
+
+ while (read < len && used)
+ {
+ size_t supply = (offset + used) > _segSize ? _segSize - offset : used;
+ size_t demand = len - read;
+ size_t chunk = supply < demand ? supply : demand;
+
+ memcpy(buf + read, seg->data + offset, chunk);
+
+ offset += chunk;
+ used -= chunk;
+ read += chunk;
+
+ if (offset == _segSize)
+ {
+ seg = seg->next;
+ offset = 0;
+ }
+ }
+
+ return read;
+}
+
+//*******************************************************************************************************************
+size_t xbuf::available()
+{
+ return _used;
+}
+
+//*******************************************************************************************************************
+int xbuf::indexOf(const char target, const size_t begin)
+{
+ char targetstr[2] = " ";
+ targetstr[0] = target;
+
+ return indexOf(targetstr, begin);
+}
+
+//*******************************************************************************************************************
+int xbuf::indexOf(const char* target, const size_t begin)
+{
+ size_t targetLen = strlen(target);
+
+ if (targetLen > _segSize || targetLen > _used)
+ return -1;
+
+ size_t searchPos = _offset + begin;
+ size_t searchEnd = _offset + _used - targetLen;
+
+ if (searchPos > searchEnd)
+ return -1;
+
+ size_t searchSeg = searchPos / _segSize;
+ xseg* seg = _head;
+
+ while (searchSeg)
+ {
+ seg = seg->next;
+ searchSeg --;
+ }
+
+ size_t segPos = searchPos % _segSize;
+
+ while (searchPos <= searchEnd)
+ {
+ size_t compLen = targetLen;
+
+ if (compLen <= (_segSize - segPos))
+ {
+ if (memcmp(target, seg->data + segPos, compLen) == 0)
+ {
+ return searchPos - _offset;
+ }
+ }
+ else
+ {
+ size_t compLen = _segSize - segPos;
+
+ if (memcmp(target, seg->data + segPos, compLen) == 0)
+ {
+ compLen = targetLen - compLen;
+
+ if (memcmp(target + targetLen - compLen, seg->next->data, compLen) == 0)
+ {
+ return searchPos - _offset;
+ }
+ }
+ }
+
+ searchPos++;
+ segPos++;
+
+ if (segPos == _segSize)
+ {
+ seg = seg->next;
+ segPos = 0;
+ }
+ }
+
+ return -1;
+}
+
+//*******************************************************************************************************************
+String xbuf::readStringUntil(const char target)
+{
+ return readString(indexOf(target) + 1);
+}
+
+//*******************************************************************************************************************
+String xbuf::readStringUntil(const char* target)
+{
+ int index = indexOf(target);
+
+ if (index < 0)
+ return String();
+
+ return readString(index + strlen(target));
+}
+
+//*******************************************************************************************************************
+String xbuf::readString(int endPos)
+{
+ String result;
+
+ if ( ! result.reserve(endPos + 1))
+ {
+ return result;
+ }
+
+ if (endPos > _used)
+ {
+ endPos = _used;
+ }
+
+ if (endPos > 0 && result.reserve(endPos + 1))
+ {
+ while (endPos--)
+ {
+ result += (char)_head->data[_offset++];
+ _used--;
+
+ if (_offset >= _segSize)
+ {
+ remSeg();
+ }
+ }
+ }
+
+ return result;
+}
+
+//*******************************************************************************************************************
+String xbuf::peekString(int endPos)
+{
+ String result;
+
+ xseg* seg = _head;
+ size_t offset = _offset;
+
+ if (endPos > _used)
+ {
+ endPos = _used;
+ }
+
+ if (endPos > 0 && result.reserve(endPos + 1))
+ {
+ while (endPos--)
+ {
+ result += (char)seg->data[offset++];
+
+ if ( offset >= _segSize)
+ {
+ seg = seg->next;
+ offset = 0;
+ }
+ }
+ }
+
+ return result;
+}
+
+//*******************************************************************************************************************
+void xbuf::flush()
+{
+ while (_head)
+ remSeg();
+
+ _tail = nullptr;
+ _offset = 0;
+ _used = 0;
+ _free = 0;
+}
+
+//*******************************************************************************************************************
+void xbuf::addSeg()
+{
+ if (_tail)
+ {
+ _tail->next = (xseg*) new uint32_t[_segSize / 4 + 1];
+ _tail = _tail->next;
+ }
+ else
+ {
+ _tail = _head = (xseg*) new uint32_t[_segSize / 4 + 1];
+ }
+
+ _tail->next = nullptr;
+ _free += _segSize;
+}
+
+//*******************************************************************************************************************
+void xbuf::remSeg()
+{
+ if (_head)
+ {
+ xseg *next = _head->next;
+ delete[] (uint32_t*) _head;
+ _head = next;
+
+ if ( ! _head)
+ {
+ _tail = nullptr;
+ }
+ }
+
+ _offset = 0;
+}
+
diff --git a/src_cpp/utility/xbuf.h b/src_cpp/utility/xbuf.h
new file mode 100644
index 0000000..e63198d
--- /dev/null
+++ b/src_cpp/utility/xbuf.h
@@ -0,0 +1,148 @@
+/****************************************************************************************************************************
+ xbuf.h - Dead simple AsyncHTTPRequest for ESP8266, ESP32 and currently STM32 with built-in LAN8742A Ethernet
+
+ For ESP8266, ESP32 and STM32 with built-in LAN8742A Ethernet (Nucleo-144, DISCOVERY, etc)
+
+ AsyncHTTPRequest_STM32 is a library for the ESP8266, ESP32 and currently STM32 run built-in Ethernet WebServer
+
+ Based on and modified from asyncHTTPrequest Library (https://github.com/boblemaire/asyncHTTPrequest)
+
+ Built by Khoi Hoang https://github.com/khoih-prog/AsyncHTTPRequest_Generic
+ Licensed under MIT license
+
+ Copyright (C) <2018>
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
+ as published bythe Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with this program. If not, see .
+
+ Version: 1.0.1
+
+ Version Modified By Date Comments
+ ------- ----------- ---------- -----------
+ 1.0.0 K Hoang 14/09/2020 Initial coding to add support to STM32 using built-in Ethernet (Nucleo-144, DISCOVERY, etc).
+ 1.0.1 K Hoang 09/10/2020 Restore cpp code besides Impl.h code.
+ *****************************************************************************************************************************/
+
+/********************************************************************************************
+ xbuf is a dynamic buffering system that supports reading and writing much like cbuf.
+ The class has it's own provision for writing from buffers, Strings and other xbufs
+ as well as the inherited Print functions.
+ Rather than use a large contiguous heap allocation, xbuf uses a linked chain of segments
+ to dynamically grow and shrink with the contents.
+ There are other benefits as well to using smaller heap allocation units:
+ 1) A buffer can work fine in a fragmented heap environment (admittedly contributing to it)
+ 2) xbuf contents can be copied from one buffer to another without the need for
+ 2x heap during the copy.
+ The segment size defaults to 64 but can be dynamically set in the constructor at creation.
+ The inclusion of indexOf and read/peek until functions make it useful for handling
+ data streams like HTTP, and in fact is why it was created.
+
+ NOTE: The size of the indexOf() search string is limited to the segment size.
+ It could be extended but didn't seem to be a practical consideration.
+
+********************************************************************************************/
+
+#pragma once
+
+#include
+
+struct xseg
+{
+ xseg *next;
+ uint8_t data[];
+};
+
+class xbuf: public Print
+{
+ public:
+
+ xbuf(const uint16_t segSize = 64);
+ virtual ~xbuf();
+
+ size_t write(const uint8_t);
+ size_t write(const char*);
+ size_t write(const uint8_t*, const size_t);
+ size_t write(xbuf*, const size_t);
+ size_t write(String);
+ size_t available();
+ int indexOf(const char, const size_t begin = 0);
+ int indexOf(const char*, const size_t begin = 0);
+ uint8_t read();
+ size_t read(uint8_t*, size_t);
+ String readStringUntil(const char);
+ String readStringUntil(const char*);
+ String readString(int);
+
+ String readString()
+ {
+ return readString(available());
+ }
+
+ void flush();
+
+ uint8_t peek();
+ size_t peek(uint8_t*, const size_t);
+
+ String peekStringUntil(const char target)
+ {
+ return peekString(indexOf(target, 0));
+ }
+
+ String peekStringUntil(const char* target)
+ {
+ return peekString(indexOf(target, 0));
+ }
+
+ String peekString()
+ {
+ return peekString(_used);
+ }
+
+ String peekString(int);
+
+ /* In addition to the above functions,
+ the following inherited functions from the Print class are available.
+
+ size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
+ size_t printf_P(PGM_P format, ...) __attribute__((format(printf, 2, 3)));
+ size_t print(const __FlashStringHelper *);
+ size_t print(const String &);
+ size_t print(const char[]);
+ size_t print(char);
+ size_t print(unsigned char, int = DEC);
+ size_t print(int, int = DEC);
+ size_t print(unsigned int, int = DEC);
+ size_t print(long, int = DEC);
+ size_t print(unsigned long, int = DEC);
+ size_t print(double, int = 2);
+ size_t print(const Printable&);
+
+ size_t println(const __FlashStringHelper *);
+ size_t println(const String &s);
+ size_t println(const char[]);
+ size_t println(char);
+ size_t println(unsigned char, int = DEC);
+ size_t println(int, int = DEC);
+ size_t println(unsigned int, int = DEC);
+ size_t println(long, int = DEC);
+ size_t println(unsigned long, int = DEC);
+ size_t println(double, int = 2);
+ size_t println(const Printable&);
+ size_t println(void);
+ */
+
+ protected:
+
+ xseg *_head;
+ xseg *_tail;
+ uint16_t _used;
+ uint16_t _free;
+ uint16_t _offset;
+ uint16_t _segSize;
+
+ void addSeg();
+ void remSeg();
+};
+