forked from khoih-prog/AsyncHTTPRequest_Generic
v1.5.0 to fix multiple-definitions linker error
### Releases v1.5.0 1. Fix `multiple-definitions` linker error and weird bug related to `src_cpp`. Check [Different behaviour using the src_cpp or src_h lib #80](https://github.com/khoih-prog/ESPAsync_WiFiManager/discussions/80) 2. Optimize library code by using `reference-passing` instead of `value-passing` 3. Update all examples
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
Version: 1.4.1
|
||||
Version: 1.5.0
|
||||
|
||||
Version Modified By Date Comments
|
||||
------- ----------- ---------- -----------
|
||||
@@ -35,6 +35,7 @@
|
||||
1.3.1 K Hoang 09/10/2021 Update `platform.ini` and `library.json`
|
||||
1.4.0 K Hoang 23/11/2021 Fix crashing bug when request a non-existing IP
|
||||
1.4.1 K Hoang 29/11/2021 Auto detect ESP32 core version and improve connection time for WT32_ETH01
|
||||
1.5.0 K Hoang 30/12/2021 Fix `multiple-definitions` linker error
|
||||
*****************************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
Version: 1.4.1
|
||||
Version: 1.5.0
|
||||
|
||||
Version Modified By Date Comments
|
||||
------- ----------- ---------- -----------
|
||||
@@ -35,6 +35,7 @@
|
||||
1.3.1 K Hoang 09/10/2021 Update `platform.ini` and `library.json`
|
||||
1.4.0 K Hoang 23/11/2021 Fix crashing bug when request a non-existing IP
|
||||
1.4.1 K Hoang 29/11/2021 Auto detect ESP32 core version and improve connection time for WT32_ETH01
|
||||
1.5.0 K Hoang 30/12/2021 Fix `multiple-definitions` linker error
|
||||
*****************************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
@@ -42,7 +43,13 @@
|
||||
#ifndef ASYNC_HTTP_REQUEST_GENERIC_H
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_H
|
||||
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_VERSION "AsyncHTTPRequest_Generic v1.4.1"
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_VERSION "AsyncHTTPRequest_Generic v1.5.0"
|
||||
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_VERSION_MAJOR 1
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_VERSION_MINOR 5
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_VERSION_PATCH 0
|
||||
|
||||
#define ASYNC_HTTP_REQUEST_GENERIC_VERSION_INT 1005000
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
@@ -98,7 +105,110 @@
|
||||
#endif
|
||||
|
||||
#include <pgmspace.h>
|
||||
#include <utility/xbuf.h>
|
||||
|
||||
// Merge xbuf
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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(const String& 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();
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define DEBUG_HTTP(format,...) if(_debug){\
|
||||
DEBUG_IOTA_PORT.printf("Debug(%3ld): ", millis()-_requestStartTime);\
|
||||
@@ -205,7 +315,7 @@ class AsyncHTTPRequest
|
||||
#endif
|
||||
|
||||
bool send(); // Send the request (GET)
|
||||
bool send(String body); // Send the request (POST)
|
||||
bool send(const 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
|
||||
@@ -292,7 +402,7 @@ class AsyncHTTPRequest
|
||||
header* _getHeader(int);
|
||||
bool _buildRequest();
|
||||
bool _parseURL(const char*);
|
||||
bool _parseURL(String);
|
||||
bool _parseURL(const String& url);
|
||||
void _processChunks();
|
||||
bool _connect();
|
||||
size_t _send();
|
||||
@@ -312,6 +422,4 @@ class AsyncHTTPRequest
|
||||
bool _collectHeaders();
|
||||
};
|
||||
|
||||
#include "AsyncHTTPRequest_Impl_Generic.h"
|
||||
|
||||
#endif // ASYNC_HTTP_REQUEST_GENERIC_H
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
Version: 1.4.1
|
||||
Version: 1.5.0
|
||||
|
||||
Version Modified By Date Comments
|
||||
------- ----------- ---------- -----------
|
||||
@@ -35,6 +35,7 @@
|
||||
1.3.1 K Hoang 09/10/2021 Update `platform.ini` and `library.json`
|
||||
1.4.0 K Hoang 23/11/2021 Fix crashing bug when request a non-existing IP
|
||||
1.4.1 K Hoang 29/11/2021 Auto detect ESP32 core version and improve connection time for WT32_ETH01
|
||||
1.5.0 K Hoang 30/12/2021 Fix `multiple-definitions` linker error
|
||||
*****************************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
@@ -44,6 +45,394 @@
|
||||
|
||||
#define CANT_SEND_BAD_REQUEST F("Can't send() bad request")
|
||||
|
||||
// Merge xbuf
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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(const 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))
|
||||
{
|
||||
// KH, to remove
|
||||
AHTTP_LOGDEBUG1("xbuf::readString: can't reserve size = ", endPos + 1);
|
||||
///////
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// KH, to remove
|
||||
AHTTP_LOGDEBUG1("xbuf::readString: Reserved size = ", endPos + 1);
|
||||
///////
|
||||
|
||||
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];
|
||||
|
||||
if (_tail->next == NULL)
|
||||
AHTTP_LOGERROR("xbuf::addSeg: error new 1");
|
||||
|
||||
// KH, Must check NULL here
|
||||
_tail = _tail->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// KH, Must check NULL here
|
||||
_tail = _head = (xseg*) new uint32_t[_segSize / 4 + 1];
|
||||
|
||||
if (_tail == NULL)
|
||||
AHTTP_LOGERROR("xbuf::addSeg: error new 2");
|
||||
}
|
||||
|
||||
// KH, Must check NULL here
|
||||
if (_tail)
|
||||
_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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//**************************************************************************************************************
|
||||
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)
|
||||
@@ -248,7 +637,7 @@ bool AsyncHTTPRequest::send()
|
||||
}
|
||||
|
||||
//**************************************************************************************************************
|
||||
bool AsyncHTTPRequest::send(String body)
|
||||
bool AsyncHTTPRequest::send(const String& body)
|
||||
{
|
||||
// New in v1.1.1
|
||||
if (_requestReadyToSend)
|
||||
@@ -602,7 +991,7 @@ bool AsyncHTTPRequest::_parseURL(const char* url)
|
||||
}
|
||||
|
||||
//**************************************************************************************************************
|
||||
bool AsyncHTTPRequest::_parseURL(String url)
|
||||
bool AsyncHTTPRequest::_parseURL(const String& url)
|
||||
{
|
||||
SAFE_DELETE(_URL)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user