Git Product home page Git Product logo

asynchttprequest's Introduction

asyncHTTPrequest

NOTE: This was originally intended for ESP8266, although it works fine for HTTP on ESP32. For a non-async version that handles HTTPS on ESP32, see the follow-on esp32HTTPrequest in this repo.

Asynchronous HTTP for ESP8266 and ESP32. Subset of HTTP. Built on ESPAsyncTCP (AsyncTCP for ESP32) Methods similar in format and use to XmlHTTPrequest in Javascript.

Supports:

  • GET and POST
  • Request and response headers
  • Chunked response
  • Single String response for short (<~5K) responses (heap permitting).
  • optional onData callback.
  • optional onReadyStatechange callback.

This library adds a simple HTTP layer on top of the ESPAsyncTCP library to facilitate REST communication from a client to a server. The paradigm is similar to the XMLHttpRequest in Javascript, employing the notion of a ready-state progression through the transaction request.

Synchronization can be accomplished using callbacks on ready-state change, a callback on data receipt, or simply polling for ready-state change. Data retrieval can be incremental as received, or bulk retrieved when the transaction completes provided there is enough heap to buffer the entire response.

The underlying buffering uses a new xbuf class. It handles both character and binary data. xbuf uses a chain of small (64 byte) segments that are allocated and added to the tail as data is added and deallocated from the head as data is read, achieving the same result as a dynamic circular buffer limited only by the size of heap. The xbuf implements indexOf and readUntil functions.

For short transactions, buffer space should not be an issue. In fact, it can be more economical than other methods that use larger fixed length buffers. Data is acked when retrieved by the caller, so there is some limited flow control to limit heap usage for larger transfers.

Request and response headers are handled in the typical fashion.

Chunked responses are recognized and handled transparently.

Testing has not been extensive, but it is a fairly lean library, and all of the functions were tested to some degree. It is working flawlessly in the application for which it was designed.

Possibly I'll revisit this in the future and add support for additional HTTP request types like PUT.

See the Wiki for an explanation of the various methods.

Following is a snippet of code using this library, along with a sample of the debug output trace from normal operation. The context is that this code is in a process that runs as a state machine to post data to an external server. Suffice it to say that none of the calls block, and that the program does other things while waiting for the readyState to become 4.

There are a few different methods available to synchronize on completion and to extract the response data, especially long responses. This is a simpler example.

  asyncHTTPrequest request;
	.
	.
	.

   case sendPost:{
      String URL = EmonURL + ":" + String(EmonPort) + EmonURI + "/input/bulk";
      request.setTimeout(1);
      request.setDebug(true);
	  if(request.debug()){
        DateTime now = DateTime(UNIXtime() + (localTimeDiff * 3600));
        String msg = timeString(now.hour()) + ':' + timeString(now.minute()) + ':' + timeString(now.second());
        Serial.println(msg);
      }
      request.open("POST", URL.c_str());
      String auth = "Bearer " + apiKey;
      request.setReqHeader("Authorization", auth.c_str());
      request.setReqHeader("Content-Type","application/x-www-form-urlencoded");
      request.send(reqData);
      state = waitPost;
      return 1;
    } 

    case waitPost: {
      if(request.readyState() != 4){
        return UNIXtime() + 1; 
      }
      if(request.responseHTTPcode() != 200){
        msgLog("EmonService: Post failed: ", request.responseHTTPcode);  
        state = sendPost;
        return UNIXtime() + 1;
      }
      String response = request.responseText();
      if( ! response.startsWith("ok")){
        msgLog("EmonService: response not ok. Retrying.");
        state = sendPost;
        return UNIXtime() + 1;
      }
      reqData = "";
      reqEntries = 0;    
      state = post;
      return UnixNextPost;
    }>

and here's what the debug trace looks like:

Debug(1991): setDebug(on)
16:47:50
Debug(1992): open(POST, emoncms.org:80/input/bulk)
Debug(  0): _parseURL() HTTP://emoncms.org:80/input/bulk
Debug(  3): _connect()
Debug(  6): send(String) time=1519854470&... (43)
Debug( 10): _buildRequest()
Debug( 12): _send() 230
Debug( 14): *can't send
Debug(190): _onConnect handler
Debug(190): _setReadyState(1)
Debug(191): _send() 230
Debug(191): *sent 230
Debug(312): _onData handler HTTP/1.1 200 OK... (198)
Debug(313): _collectHeaders()
Debug(315): _setReadyState(2)
Debug(315): _setReadyState(3)
Debug(315): *all data received - closing TCP
Debug(319): _onDisconnect handler
Debug(321): _setReadyState(4)
Debug(921): responseText() ok... (2)

asynchttprequest's People

Contributors

andreas-provectusalgae avatar boblemaire avatar danielbuechele avatar legrems avatar miwied avatar nilskrause avatar ramarro123 avatar sakinit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

asynchttprequest's Issues

Connection not Closing

This is not a bug, it's likely me being a dumba%$, but I'm willing to accept ridicule right now. I am unit testing some code and POSTing a JSON to a PHP endpoint just to get the code working. It looks as if the session never closes, therefore the onData callback keeps firing. If I were to place money on it, I'd say I messed up my PHP somewhere but I am not sure where.

Here's my C++ code snippet:

asyncHTTPrequest postobject;

void sendPost()
{
	// Do stuff here to make the json
	
	postobject.onData(resultHandler);
	if (postobject.readyState() == 0 || postobject.readyState() == 4)
	{
		Log.verbose(F("DEBUG: About to send JSON." CR));    // DEBUG
		Serial.println(json.c_str());                       // DEBUG
		postobject.setDebug(true);                          // DEBUG

		postobject.setTimeout(5);
		postobject.open("POST", "http://host.com/api.php");
		postobject.setReqHeader("Content-Type","application/json");
		postobject.send(json.c_str());
	}
	else
	{
		Log.verbose(F("DEBUG: Previous post still in progress." CR));
	}
}

void resultHandler(void* optParm, asyncHTTPrequest* report, int readyState) {
    if (readyState == 4)
    {
		if (report->responseHTTPcode() == 200)
		{
			Log.notice(F("HTTP response code %d received ($dms). The request was successfully received, understood, and accepted." CR), report->responseHTTPcode(), report->elapsedTime());
        }
    }
}

And here is the receiving PHP code:

<?php

$debug = true;                                  // Write log file if true
$file = "api.txt";                           // API Log
$args = "LOCK_EX | FILE_APPEND";                // File lock mode
$json = file_get_contents('php://input');       // Get incoming post

function writeLog($logLine) { // Log file writer (if $debug == true)
    global $debug;
    if ($debug) {
        // Get timestamp
        $date = date('Y-m-j H:m:s  ', time());
        //Open the File Stream
        global $file;
        $handle = fopen($file, "a");

        //Lock File, error if unable to lock
        if (flock($handle, LOCK_EX)) {
            fwrite($handle, $date);
            fwrite($handle, $logLine);
            fwrite($handle, "\n");
            flock($handle, LOCK_UN);
        }
    }
}

$result = json_decode($json);

if (json_last_error() === JSON_ERROR_NONE) { // JSON is valid
    writeLog("Received JSON: " . $json);
    header("HTTP/1.1 200 OK");
    echo "Ok\n\n";
} else {
    // Unable to decode JSON
    writeLog("Invalid JSON received.");
    header("HTTP/1.1 400 Bad Request");
    echo "Invalid JSON received.";
}

?>

Here's my serial log when this fires:

2020-07-14T14:51:45Z V: DEBUG: About to send JSON.
Debug(15859): setDebug(on) version 1.1.15
Debug(15865): setTimeout(5)
Debug(15866): open(POST, http://192.168.168.xxx/api.ph)  
Debug(  0): _parseURL() HTTP://192.168.168.xxx:80/api.php
Debug(  5): _connect()
Debug( 12): send(char*) {"dummy":"json"}.16... (165)                     <-- (JSON redacted)
Debug( 25): _buildRequest()
Debug( 28): _send() 270
Debug( 29): *can't send
Debug( 62): _onConnect handler
Debug( 63): _setReadyState(1)
Debug( 63): _send() 270
Debug( 65): *sent 270
... (153)): _onData handler HTTP/1.1 200 OK
Debug( 72): _collectHeaders()
Debug( 73): _setReadyState(2)
Debug( 73): _setReadyState(3)
Debug( 74): *all data received - no disconnect
Debug( 59): _setReadyState(4)
2020-07-14T15:13:57Z N: HTTP response code 200 received (59ms). The request was successfully received, understood, and accepted.
2020-07-14T15:13:57Z N: HTTP response code 200 received (59ms). The request was successfully received, understood, and accepted.
[...]

The last line repeats every second or so till the next POST event.

As I said, the Debug( 74): *all data received - no disconnect points to me not doing something right at the webserver level. Does my problem jump out at you?

Feature request: make readyStates public

Hi and thanks for sharing this library.

Wouldn't it be better if we (users of this library) could use

void some_callback(void* optParm, asyncHTTPrequest* request, int readyState)
{
    if(readyState == readyStateDone)
    {

instead of

void some_callback(void* optParm, asyncHTTPrequest* request, int readyState)
{
    if(readyState == 4)
    {

Currently (v.1.2.2) I see this in asyncHTTPrequest.h:

  private:
...
    enum    readyStates {
                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} _readyState; // Request complete, all data available.

Maybe moving this enum definition to the public: part would already solve this feature request?

Thank you,
Kind regards,
woutput

Hello

looks promising for my project, an ESP 3d controller that download Gcodes from my server , or to report to server. Currently i am using standard httpclient library and its pause the machine every time its report to server using http client.

    if (cmd == "print") {
      zprintf(PSTR("Download & Print:\n"));
      String durl = "http://172.245.97.171/download?gid=" + par;
      File f = SPIFFS.open("/gcode", "w");
      if (f) {
        http.begin(durl);
        int httpCode = http.GET();
        if (httpCode > 0) {
          if (httpCode == HTTP_CODE_OK) {
            Serial.println(durl);
            Serial.println(http.getSize());
            http.writeToStream(&f);
          }
        } else {
          zprintf(PSTR("Error download"));//[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
        }
        http.end();
        f.close();
        beginuncompress();
      }
    }

but i am confuse how to implement it on async. can you help me ?

thanks.

assert failed: block_trim_free

Hello, I find it works pretty good when server's response content size is not very big, but when request a content larger than 5KB, that is 5.78KB, it will crash always.

I read the readme again, noticed you have mentioned this,
"Single String response for short (<~5K) responses (heap permitting)."
I wonder is it possible to achive this goal?

Here's the backtrace, I have tried different arduino-frameworks, the same result, I doubt it is a heap related issue, but have no idea after digger for two days.

Any help will be appreciated!!!

#0 0x40083abd:0x3ffd6f20 in panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:408
#1 0x4008e201:0x3ffd6f40 in esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:137
#2 0x40094669:0x3ffd6f60 in __assert_func at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/assert.c:85
#3 0x40093636:0x3ffd7090 in block_locate_free at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_tlsf.c:441
(inlined by) tlsf_malloc at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_tlsf.c:849
#4 0x40094037:0x3ffd70b0 in multi_heap_malloc_impl at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/multi_heap.c:200
#5 0x400942a4:0x3ffd70d0 in multi_heap_malloc at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/multi_heap_poisoning.c:230
(inlined by) multi_heap_malloc at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/multi_heap_poisoning.c:219
#6 0x40083ece:0x3ffd70f0 in heap_caps_malloc_base at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:154
(inlined by) heap_caps_malloc_base at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:99
#7 0x40084013:0x3ffd7120 in heap_caps_realloc_base at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:375
#8 0x4008412a:0x3ffd7140 in heap_caps_realloc_default at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/heap/heap_caps.c:242
#9 0x40094689:0x3ffd7160 in realloc at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/newlib/heap.c:34
#10 0x4010c5c3:0x3ffd7180 in String::changeBuffer(unsigned int) at C:/Users/PP/.platformio/packages/framework-arduinoespressif32/cores/esp32/WString.cpp:200 (discriminator 4)
#11 0x4010c638:0x3ffd71c0 in String::reserve(unsigned int) at C:/Users/PP/.platformio/packages/framework-arduinoespressif32/cores/esp32/WString.cpp:165 (discriminator 4)
#12 0x4010a1c2:0x3ffd71e0 in xbuf::readString(int) at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:329
#13 0x4010a485:0x3ffd7200 in AsyncHTTPRequest::responseText() at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:1014
#14 0x40109a3a:0x3ffd7240 in std::_Function_handler<void (void*, AsyncHTTPRequest*, int), AsyncRequest::sendRequest(String const&)::{lambda(void*, AsyncHTTPRequest*, int)#1}>::_M_invoke(std::_Any_data const&, void*&&, AsyncHTTPRequest*&&, int&&) at lib/async_http/async_requests.cpp:68
(inlined by) _M_invoke at c:\users\pp.platformio\packages\[email protected]+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:297
#15 0x40195657:0x3ffd7280 in std::function<void (void*, AsyncHTTPRequest*, int)>::operator()(void*, AsyncHTTPRequest*, int) const at c:\users\pp.platformio\packages\[email protected]+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:687
(inlined by) AsyncHTTPRequest::_setReadyState(reqStates) at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:1446
(inlined by) AsyncHTTPRequest::_setReadyState(reqStates) at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:1438
#16 0x4010b6cd:0x3ffd72b0 in AsyncHTTPRequest::_onData(void*, unsigned int) at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:1666
(inlined by) AsyncHTTPRequest::_onData(void*, unsigned int) at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:1618
#17 0x4010b709:0x3ffd72e0 in std::_Function_handler<void (void*, AsyncClient*, void*, unsigned int), AsyncHTTPRequest::_onConnect(AsyncClient*)::{lambda(void*, AsyncClient*, void*, unsigned int)#2}>::_M_invoke(std::_Any_data const&, void*&&, AsyncClient*&&, std::_Any_data const&, unsigned
int&&) at lib/async_http/AsyncHTTPRequest_Impl_Generic.cpp:1533
(inlined by) _M_invoke at c:\users\pp.platformio\packages\[email protected]+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:297
#18 0x401819aa:0x3ffd7300 in std::function<void (void*, AsyncClient*, void*, unsigned int)>::operator()(void*, AsyncClient*, void*, unsigned int) const at c:\users\pp.platformio\packages\[email protected]+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h:687
(inlined by) AsyncClient::_recv(tcp_pcb*, pbuf*, signed char) at .pio/libdeps/bigtvlite/AsyncTCP/src/AsyncTCP.cpp:915
#19 0x40181a99:0x3ffd7330 in AsyncClient::_s_recv(void*, tcp_pcb*, pbuf*, signed char) at .pio/libdeps/bigtvlite/AsyncTCP/src/AsyncTCP.cpp:1191
#20 0x40182002:0x3ffd7350 in _async_service_task(void*) at .pio/libdeps/bigtvlite/AsyncTCP/src/AsyncTCP.cpp:159
(inlined by) _async_service_task at .pio/libdeps/bigtvlite/AsyncTCP/src/AsyncTCP.cpp:194

Issue when assigning result to a string

Hi I've used the sample and it works, however I cannot assign the result to a string. It just prints blank in the serial monitor.
if(readyState == 4){
Serial.println(request->responseText());
String responseResult = request->responseText();
Serial.println(responseResult);
Could you explain how to do this?
Stephen Leach

Basic 'Hello world' example please.

I would imagine that most users of this library want to make a non-blocking HTTP GET request and get back the response as a string. I'm sure thats possible... But with the current documentation it would require quite some digging.

HTTP:// in URL is case sensitive, won't accept http://

i am not 100% it's intended but, without documentation it's hard so i dig a bit on code and found

_URL->scheme = new char[8];
strcpy(_URL->scheme, "HTTP://");
if(url.startsWith("HTTP://")) {
   hostBeg += 7; 
}

my url was http:// and it doesn't work... converting it with uppercase make it work apparently.
doing a touppercase doesn't seems a good idea, cos parameters get uppercase as well.

Compilation error on ESP8285 and PlatformIO

Hi,
I've used asyncHTTPrequest with success in the Arduino IDE.
Now, I try to compile the same program in PlatformIO (I have added lib_deps = khoih.prog/AsyncHTTPRequest_Generic@^1.1.2 in the platformio.ini file) and compilation gives a lot of error. The first one is .pio\libdeps\esp8285\STM32Ethernet\src\utility/stm32_eth.h:42:23: fatal error: stm32_def.h: No such file or directory
Compile a blank programm with just empty setup() and empty loop() with lib_deps = khoih.prog/AsyncHTTPRequest_Generic@^1.1.2 in the platformio.ini file gives the same error.
Thanks for your help.
Eric

Edit : it works after deleting STM32 files from the .pio/libdeps directory.

"Off by one" error in header values ?

There seems to be an "off by one" error in

asyncHTTPrequest::_addHeader(const char* name, const char* value)`

An HTTP request made with curl looks like this:

~curl "http://192.168.1.55:8080/json.htm" 
OK

Received request() from 192.168.1.208:50882
  request->method: GET (1)
  request->url() = "/json.htm"
  request->headers() = 3
    1 Host: 192.168.1.55:8080
    2 Accept: */*
... 

The same HTTP request made with asyncHTTPrequest (code below) looks like this:

Received request() from 192.168.1.135:65086
  request->method: GET (1)
  request->url() = "/json.htm"
  request->headers() = 2
    1 host: 92.168.1.55:8080
    2 Accept: /*

Note how the first char of each header value is missing. To confirm the error add a space in front of the Accept value when making the request with asyncHTTPrequest

void sendRequest(){
	if (request.readyState() == 0 || request.readyState() == 4) {
		request.setTimeout(2);
		bool requestOpenResult = request.open("GET", "http://192.168.1.55:8080/json.htm");
		if (requestOpenResult) {
		  request.setReqHeader("Accept", " */*");    //<===== space added before *
      request.send();
		  Serial.println("Request sent");
		}
		else
		  Serial.println("Error: could not open request");
	} else {
	 Serial.println("request is not ready");
	}
}

and a space in front of the host name in asyncHTTPrequest::open(const char* method, const char* URL)
at line 93

    char* hostName = new char[strlen(_URL->host)+10];
    sprintf(hostName," %s:%d", _URL->host, _URL->port);    //<===== space added before %s
    _addHeader("host",hostName);

then the headers are correct.

Received request() from 192.168.1.135:57547
  request->method: GET (1)
  request->url() = "/json.htm"
  request->headers() = 2
    1 host: 192.168.1.55:8080
    2 Accept: */*

This was tested with an ESP32 and ESP32-C3 with the latest version of 'me-no-dev/AsyncTCP' last updated in Oct. 2019.

Looking at the code for _addHeader and then _buildRequest, it all seems OK to me. But then I'm lost at C when it comes to C/C++.

Missing library.properties

The repository is missing the library.properties file to be able to use this library with Arduino IDE.

Suggested content:

name=asyncHTTPrequest
version=1.2.1
author=Bob Lemaire
maintainer=Bob Lemaire
sentence=Simple async HTTP to sit on ESPAsyncTCP.
paragraph=Simple async HTTP to sit on ESPAsyncTCP.
category=Communication
url=https://github.com/boblemaire/asyncHTTPrequest.git
architectures=*

HTTPS

Hello.

Does it support https?

Want to make 2 different requests, but how to say to the "void requestCB" function to which requests the result belongs ?

Hello !

Rather a question than an issue :

I'm new to asyncHTTPrequest.
I generally use the standard HTTPClient, but I'm looking for an asynchronous solution.

I did try the code in the "Examples" section and it works fine to extract one value (in my case "Pedf")
But I would like to extract another value from another request at a different url.
So in my sketch I prepared 2 functions to call, "sendRequest_0()" and "sendRequest_1()"

But how to say to the "void requestCB(......" function which value to extract ?

I think there must be a very simple solution, but I'm not familiar with the syntax of this library.

Thanks in advance for any help !

Roland

Here my code for a better understanding (runs on an ESP32)

#include <WiFi.h>
#include <AsyncTCP.h>
#include <asyncHTTPrequest.h>

unsigned long top_lect;
int intervalle = 5000 ; 

const char* ssid     = "xxxxxxxxxx";
const char* password = "yyyyyyyyyyyyyyy";
const int TimeOut_connexion =40;
int timeOut_counter =0;

float Pedf;
float Psol;

asyncHTTPrequest request;

// First request
void sendRequest_0()   // to gather the responseText() for the "Pedf" value
{
    if(request.readyState() == 0 || request.readyState() == 4)
    {
        request.open("GET", "http://192.168.1.12/emeter/0");
        request.send();
    }
}

/*********** The second request I would like to make  ********************
*
*void sendRequest_1()   //    // to gather the responseText() for a second value
*{
*    if(request.readyState() == 0 || request.readyState() == 4)
*    {
*        request.open("GET", "http://192.168.1.12/emeter/1");
*        request.send();
*    }
*}
*
************ The second request I would like to make END *****************/

void requestCB(void* optparm, asyncHTTPrequest* request, int readyState)
{
    if(readyState == 4)
    {
 //       Serial.println(request->responseText());
        Pedf = atof(((request->responseText()).substring(9,18)).c_str());
        Serial.println(Pedf);
    }
}
    

void setup()
{
  setCpuFrequencyMhz(80);     // rรฉglage de la frรฉquence de la CPU (80, 160 ou 240 Mhz, en dessous le WiFi ne marche pas)

  Serial.begin(115200);
  delay(2000);

  Serial.print("Connection au WiFi...");
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
    {
      delay(250);
      Serial.print(".");
      timeOut_counter++;
      if (timeOut_counter > TimeOut_connexion) ESP.restart();   // redรฉmarrage de l'ESP si pas de connexion pendant 10 sec
    }

  Serial.println("\n");
  Serial.println("Adresse IP : "+(WiFi.localIP().toString()));

  request.onReadyStateChange(requestCB);

}

void loop() 
{
  if (top_lect+intervalle<millis())             // condition vraie toutes les "intervalle" secondes
    {top_lect=millis(); sendRequest_0(); }        // aller ร  la routine de lecture des donnรฉes du ShellyEM
}

ESP32 crashes when making simultaneous requests with 2 instances

So im making a project that needs to deal with 2 simultaneous requests so i have created 2 instances of asyncHTTPrequest and i call one per request i need to do. Example code below:

void CountinoWebConfig::publishCounts2(counterData_t counterData){
    //retrieve last counter data formatted
    String lastCounterData = formatData(counterData.sequenceNum, myTimeTracker.getLocalUnixTimeString(), counterData.periodDurationMs, counterData.countsInThisPeriod,counterData.totalCounts, counterData.minCountsPerSecondInThisPeriod, counterData.maxCountsPerSecondInThisPeriod);
    //insert data in buffer if space available
    if ( myConfigFromPortal.UploadAPI != (char*)"" ){
        if (_requestBuffer_Counter < CWC_REQUESTBUFFERLEN){
            _requestBuffer[_requestBuffer_Counter] = lastCounterData;
            _requestBuffer_Counter++;
        }

        //append previous buffered reccords
        String allData = "";
        for (uint16_t i= 0 ; i<_requestBuffer_Counter; i++){
            if (i==0){
                allData += _requestBuffer[i];
            }else{
                allData+=','+_requestBuffer[i];
            }
        }

        String dataToSend = getJSON(allData);   //jsonify data     

        if (_hasConnectivity && ! _isPublishing){
            Serial.print("[CountinoWebConfig] Will Send POST\n");
            _isPublishing = true;
            request.setDebug(true);

            //prepare request callback
            request.onReadyStateChange([this](void* optParm, asyncHTTPrequest* request, int readyState){
                if(readyState == 4){
                    int httpCode = request->responseHTTPcode();
                    Serial.printf("[CountinoWebConfig] HTTP response text : %s\n", request->responseText().c_str());
                    Serial.printf("[CountinoWebConfig] HTTP CODE is: %d\n ", httpCode );
                    if (httpCode == 200){
                        signalPortalPushSuccess(true);
                        _requestBufferCustomUrl_Counter=0;
                    }else{
                        signalPortalPushSuccess(false);
                    }
                    request->setDebug(false);
                    _isPublishing = false;
                }
            });
            //send request
            if(request.readyState() == 0 || request.readyState() == 4){
                request.open("POST", myConfigFromPortal.UploadAPI.c_str());
                request.setReqHeader("Connection", "close");
                request.setReqHeader("Content-Type", "application/json");
                request.setReqHeader("Content-Length", String(dataToSend.length()).c_str());
                request.send(dataToSend);
            }
        }else{
            signalPortalPushSuccess(false);
        }
    }

    //Do the same for custom portal
    //insert data in buffer if space available
    if ( myConfigFromPortal.data_destination_detail != (char*)"" ){
        if (_requestBufferCustomUrl_Counter < CWC_REQUESTBUFFERLEN){
            _requestBufferCustomUrl[_requestBufferCustomUrl_Counter] = lastCounterData;
            _requestBufferCustomUrl_Counter++;
        }

        //append previous buffered reccords
        String allData = "";
        for (uint16_t i= 0 ; i<_requestBufferCustomUrl_Counter; i++){
            if (i==0){
                allData += _requestBufferCustomUrl[i];
            }else{
                allData+=','+_requestBufferCustomUrl[i];
            }
            
        }
        String dataToSend = getJSON(allData); //jsonify data       
        
        if (_hasConnectivity && !_isPublishingCustom){
            Serial.print("[CountinoWebConfig] Will Send POST to Custom URL\n");
            _isPublishingCustom = true;
            requestCustom.setDebug(true);

            requestCustom.onReadyStateChange([this](void* optParm, asyncHTTPrequest* requestCust, int readyState){
                if(readyState == 4){
                    int httpCode = requestCust->responseHTTPcode();
                    Serial.printf("[CountinoWebConfig] HTTP response text : %s\n", requestCust->responseText().c_str());
                    Serial.printf("[CountinoWebConfig] HTTP CODE is: %d\n ", httpCode );
                    if (httpCode == 200){
                        signalCustomPortalPushSuccess(true);
                        _requestBufferCustomUrl_Counter=0;
                    }else{
                        signalCustomPortalPushSuccess(false);
                    }
                    requestCust->setDebug(false);
                    _isPublishingCustom = false;
                }
            });

            if(requestCustom.readyState() == 0 || requestCustom.readyState() == 4){
                requestCustom.open("POST", myConfigFromPortal.data_destination_detail.c_str());
                requestCustom.setReqHeader("Connection", "close");
                requestCustom.setReqHeader("Content-Type", "application/json");
                requestCustom.setReqHeader("Content-Length", String(dataToSend.length()).c_str());
                requestCustom.send(dataToSend);
            }
        }else{
            signalCustomPortalPushSuccess(false);
        }
    }
}

/////////////////////////// OUTPUT /////////////////////

[PulseCounterEnhanced] Will Do publish
[TimeTracker] UTC: 1590402409[CountinoWebConfig] Will Send POST
Debug(60011): setDebug(on) version 1.1.15
Debug(60015): open(POST, http://wifi-counter.cloud/backen)
Debug(  0): _parseURL() HTTP://wifi-counter.cloud:80/backend/api/admin/add_record/
Debug(  8): _connect()
Debug( 14): send(String) {
 "regId" : "$1... (81)
Debug( 15): _buildRequest()
Debug( 17): _send() 225
Debug( 19): *can't send
[CountinoWebConfig] Will Send POST to Custom URL
Debug(60045): setDebug(on) version 1.1.15
Debug(60049): open(POST, http://192.168.1.238:8080)
Debug(  0): send(String) {
 "regId" : "$1... (81)
Debug(  5): _buildRequest()
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400014fd  PS      : 0x00060e30  A0      : 0x800df248  A1      : 0x3ffb1c40  
A2      : 0x00000000  A3      : 0xfffffffc  A4      : 0x000000ff  A5      : 0x0000ff00  
A6      : 0x00ff0000  A7      : 0xff000000  A8      : 0x00000000  A9      : 0x0000003b  
A10     : 0x00000005  A11     : 0x3f40330f  A12     : 0x00000005  A13     : 0x3ffd59c4  
A14     : 0x00000020  A15     : 0x2054534f  SAR     : 0x00000018  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff  

Backtrace: 0x400014fd:0x3ffb1c40 0x400df245:0x3ffb1c50 0x400de1a9:0x3ffb1c70 0x400de9a2:0x3ffb1c90 0x400e3382:0x3ffb1cc0 0x400d1716:0x3ffb1d80 0x400e497d:0x3ffb1e00 0x400d1963:0x3ffb1f90 0x400e6cad:0x3ffb1fb0 0x40088c99:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5828
entry 0x400806ac

Not sure if im making anything wrong or its the library not handling properly the soimultaneous requests. I did a similar library before but changed to this one because it felt more complete. Help is much appreciated please!

https?

Do you think it is possible/feasible to implement https?
I have almost zero knowledge about tls but willing to dive in.

Crash after second request to not accessible target

I have an ESP8266 IOT sending "push messages" to a NodeJS server. All works fine as long as the server is available and responds to the requests.

If however the server is not available then I get the following behavior.

  • IOT sends first request after initialization : http.readyState() before sending is 0. A callback with a response code of -4 is generated after approx. 30 secs. Setting http.setTimeout to a large (60) or small (1) value has no impact on this timeout.
  • If you wait until the first request "times out" before the IOT sends its second request then you get a http.readyState() before sending of 4 and when the second packet times out with a response code of -4 all is good
  • If you wait until the second request "times out" before the IOT sends its third request then you get a http.readyState() before sending of 4 and when the third request times out with a response code of -4 all is good
  • If however the IOT sends its third request before receiving the -4 response code (associated with the second request) the http.readyState() before sending is 0. When the second request times out with a response code of -4 all is good. However when the third request times out the ESP restarts immediately.

If I modify my code to only send on a http.readyState() of 4 after the first request is sent (after initialization the http.readyState() is always 0) then the crashes are avoided.

Questions:

  1. Is it possible to decrease the "-4" timeout when the remote device is not available.
  2. Is there any way to avoid the crash other than by only sending requests (after the initial one) when the http.readyState() is 4?

Thanks for your help with this one.

Can't make secure HTTP (HTTPS) request

Hi everyone,

I'm unable to perform requests to HTTPS Endpoints. the requests are failing with exception.

Let me know if you guys need the logs.

Thank you.

Random crashes in asyncHTTPrequest::_onDisconnect

Occasionally, the ESP32 crashes when trying to delete _client in asyncHTTPrequest::_onDisconnect or when trying to call asyncHTTPrequest::_onDisconnect.

The first scenario seems to happen when for some reason asyncHTTPrequest::_onDisconnect is called for the same asyncHTTPrequest instance and the same AsyncClient instance within very short time (1 or 2 ms).
It seems to happen when a connection times out.
In this scenario I get "CORRUPT HEAP: Bad head at 0x3ffdfa60. Expected 0xabba1234 got 0x3ffdfff8".

Stack trace for scenario 1:

0x4008c4b4: invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 155
0x4008c6e5: abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c line 170
0x4013731b: __assert_func at ../../../.././newlib/libc/stdlib/assert.c line 63
0x4008c129: multi_heap_free at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/heap/multi_heap_poisoning.c line 214
0x40084b5a: heap_caps_free at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/heap/heap_caps.c line 268
0x40084f61: _free_r at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/newlib/syscalls.c line 42
0x4016a369: operator delete(void*) at /Volumes/build/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/del_op.cc line 46
0x400e1ae6: asyncHTTPrequest::_onDisconnect(AsyncClient*) at ~/Documents/Arduino/libraries/asyncHTTPrequest/src/asyncHTTPrequest.cpp line 510
0x400e1b29: std::_Function_handler >::_M_invoke(const std::_Any_data &, private/var/folders/22/x3rnxz554qq_0ddwr14cm80c0000gn/T/arduino_build_673379/ProvectusAlgaeBioreactorG5MasterController.ino.elf, CU 0x27474b, DIE 0x27f521>, private/var/folders/22/x3rnxz554qq_0ddwr14cm80c0000gn/T/arduino_build_673379/ProvectusAlgaeBioreactorG5MasterController.ino.elf, CU 0x27474b, DIE 0x27f526>) at ~/Documents/Arduino/libraries/asyncHTTPrequest/src/asyncHTTPrequest.cpp line 334
0x400e3112: std::function::operator()(void*, AsyncClient*) const at ~/Library/Arduino15/packages/esp32/tools/xtensa-esp32-elf-gcc/1.22.0-80-g6c4433a-5.2.0/xtensa-esp32-elf/include/c++/5.2.0/functional line 2271
0x400e3262: AsyncClient::_fin(tcp_pcb*, signed char) at ~/Documents/Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp line 907
0x400e3278: AsyncClient::_s_fin(void*, tcp_pcb*, signed char) at ~/Documents/Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp line 1214
0x400e3502: _async_service_task(void*) at ~/Documents/Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp line 165
0x40088bc5: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

The second scenario seems to happen when asyncHTTPrequest::_onConnect is called just before asyncHTTPrequest::_onDisconnect for the same asyncHTTPrequest instance and the same AsyncClient instance is supposed to be called.
This seems to happen when a new request is started just before the connection is timing out.
In this scenario I get HTTPCODE_CONNECTION_LOST and then "Guru Meditation Error: Core 1 panic'ed (InstrFetchProhibited). Exception was unhandled.".

Stack trace for scenario 2:

0x400e326c: AsyncClient::_s_fin(void*, tcp_pcb*, signed char) at ~/Documents/Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp line 1215
0x400e34f6: _async_service_task(void*) at ~/Documents/Arduino/libraries/AsyncTCP/src/AsyncTCP.cpp line 166
0x40088bc5: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

The code in asyncHTTPrequest seems to be thread-safe. I'm not sure how it is possible that asyncHTTPrequest::_onDisconnect tries to delete the same object twice when the mutex should have locked access to it and changed it to nullptr, before the lock is released and the second call is accessing it?!
Currently, I see three possible problems: a bug in the compiler, a bug in FreeRTOS or a bug (missing locks?) in AsyncTCP, but all I can tell so far is that asyncHTTPrequest has crashes sometimes when asyncHTTPrequest::_onDisconnect is (supposed to be) called.

Following redirects?

I am a bit of a n00b when it comes to the fundamental principles of how the HTTP protocol works in depth.

When I receive a 301 redirect response, how should I handle this? Should I close the existing request and allocate a new request using the new location URL? Or is there an easier/better way to do it?

I am thinking about making a PR to add an option for automatically following redirects but I am not sure of the best approach

Question: Use of Optional Argument in asyncHTTPRequest::onReadyStateChange()

Bob,

I need to say I understand that this is my problem, not yours - I'm just hoping you have time to give me a pointer. This is sort of a follow-up to Question: Identifying Caller in Callback #25. Basically, I have 1-N request types which I might be using and hope to re-use a function that actually sends the data. The callback needs to know the calling function's context in order to meet my needs.

The plan was to pass a variable to the callback, and thereby identify which report it is that's being handled. The only way I am able to do this is by &reference. When I do that, the original variable goes out of scope from the caller. I can prove that by adding a delay() in my calling function so that it's still "alive" when the callback fires.

Here's my header:

#ifndef _MYASYNC_H
#define _MYASYNC_H

#include <asyncHTTPrequest.h>
#include <AsyncTCP.h>
#include <ArduinoLog.h>
#include <Arduino.h>

enum ReportKey
{
    MY_REPORT0,
    MY_REPORT1,
    MY_REPORT2,
    MY_REPORT3,
    MY_REPORT4
};

void sendRequest();
void requestCB(void *, asyncHTTPrequest *, int);

#endif // _MYASYNC_H

And the code:

#include "myAsync.h"

asyncHTTPrequest
    request0,
    request1,
    request2,
    request3,
    request4;

asyncHTTPrequest reports[5] = {
    request0,
    request1,
    request2,
    request3,
    request4
};

const char *reporttype[5] = {
    "request0",
    "request1",
    "request2",
    "request3",
    "request4"
};

const char *reportname[5] = {
    "Request 0",
    "Request 1",
    "Request 2",
    "Request 3",
    "Request 4"
};

void sendRequest()
{
    ReportKey reportkey = MY_REPORT0;
    //reports[reportkey].setDebug(true);
    Log.verbose(F("DEBUG: Sending: '%s' report (%d)." CR), reportname[reportkey], reportkey);
    reports[reportkey].onReadyStateChange(requestCB, &reportkey);
    if (reports[reportkey].readyState() == 0 || reports[reportkey].readyState() == 4)
    {
        reports[reportkey].open("GET", "http://1.1.1.1/");
        reports[reportkey].send();
    }
}

void requestCB(void *optParm, asyncHTTPrequest *request, int readyState)
{
    if (readyState == 4)
    {
        ReportKey reportkey = *(ReportKey*)optParm;
        // const int *__attribute__((unused)) reportkey = static_cast<const int *>(optParm);
        //const char *__attribute__((unused)) thisReport = (reportkey >= 0 && reportkey <= 4) ? reportname[reportkey] : "";
        const int __attribute__((unused)) code = (request->responseHTTPcode() >= 0 && request->responseHTTPcode() <= 599) ? request->responseHTTPcode() : 0;
        const int __attribute__((unused)) elapsed = (request->elapsedTime() >= 0) ? request->elapsedTime() : 0;
        const char *__attribute__((unused)) response = (request->responseText()) ? request->responseText().c_str(): "";

        Log.verbose(F("DEBUG: Return Code: %d, Elapsed: %d, reportkey: '%d'." CR), code, elapsed, reportkey);
    }
}

The results are (predictably) inconsistent:

    428858 V: DEBUG: Return Code: 301, Elapsed: 26, reportkey: '0'.
    433831 V: DEBUG: Sending: 'Request 0' report (0).
    433860 V: DEBUG: Return Code: 301, Elapsed: 27, reportkey: '397088'.
    438831 V: DEBUG: Sending: 'Request 0' report (0).
    438854 V: DEBUG: Return Code: 301, Elapsed: 22, reportkey: '1073431156'.
    443831 V: DEBUG: Sending: 'Request 0' report (0).
    443851 V: DEBUG: Return Code: 301, Elapsed: 19, reportkey: '0'.

I understand why, but since you have this functionality there I'm relatively certain what I need is possible and I'm just too dense to get it. Any assistance would be appreciated.

- Lee

Doesn't work with binary data

Just posting this issue to let folks know that the Stream buffers don't work with binary data. I'm reworking the buffering to accommodate. Should be a few days.

Invalid zip

Hi there,
I could not use the zip file downloaded here in the Arduino IDE. Ist complaining About an invalid library Format. Could you please have a look?
Thanks!

URL without trailing '/' after address causes crash on ESP32

When attempting to connect to a HTTP server, I found that URLs where the address portion was not ended with a '/' character caused a crash.

URLs that cause crash: http://172.105.151.207, http://172.105.151.207:1230, http://172.105.151.207:1230?foo=bar
URLs that don't cause crash: http://172.105.151.207/, http://172.105.151.207:1230/, http://172.105.151.207:1230/?foo=bar.

(Note: The IP address, especially port 1230, will likely change in the future, but I hope you see the pattern).

It's easy enough to fix on my end by adding a '/' to the URL between the address and the arguments, but this shouldn't be happening.

Strange issue with ESP32

Hello and thank you for the lib!

I use it with ESP8266 and ESP32 with the same code.

No problem with ESP8266, but with ESP32, when I run multiple requests, I have an error like this:

assert failed: xQueueGenericSend queue.c:832 (pxQueue->pcHead != ((void *)0) || pxQueue->u.xSemaphore.xMutexHolder == ((void *)0) || pxQueue->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle())


Backtrace: 0x40083671:0x3ffd5140 0x4008bd65:0x3ffd5160 0x40091331:0x3ffd5180 0x4008c81a:0x3ffd52b0 0x4014ca9d:0x3ffd52f0 0x40149c8b:0x3ffd5310 0x400da087:0x3ffd5330 0x400d3476:0x3ffd5370 0x400d6915:0x3ffd53e0 0x40161d67:0x3ffd54c0 0x400dbc11:0x3ffd54e0 0x400dc416:0x3ffd5510 0x400dc672:0x3ffd5550 0x400dc7be:0x3ffd55b0 0x400dc825:0x3ffd55e0 0x4014a621:0x3ffd5600 0x4014a675:0x3ffd5630 0x4014ab8a:0x3ffd5650


ELF file SHA256: f3850e2f88f105c1

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13232
load:0x40080400,len:3028
entry 0x400805e4

But, very strange, if I setDebug to true on each instance of asyncHTTPrequest, the issue don't occur.

Many thanks and best regards.

Crash on Loading Data

When working with a debug version of a Django website, I noted that with a large document (this one was ~136k) the system will crash, I assume based on an overflow:

abort() was called at PC 0x40188863 on core 1
Backtrace: 0x4008c654:0x3ffd7f30 0x4008c885:0x3ffd7f50 0x40188863:0x3ffd7f70 0x401888aa:0x3ffd7f90 0x401883e9:0x3ffd7fb0 0x4018813c:0x3ffd7fd0 0x401880e9:0x3ffd7ff0 0x40110bcf:0x3ffd8010 0x40110c2e:0x3ffd8030 0x401107c1:0x3ffd8050 0x401108ed:0x3ffd8070 0x40189e91:0x3ffd8090 0x40189ee5:0x3ffd80c0 0x40189f29:0x3ffd80e0 0x4018a036:0x3ffd8100 0x4018a105:0x3ffd8120 0x40088c11:0x3ffd8150
  #0  0x4008c654:0x3ffd7f30 in invoke_abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:707
  #1  0x4008c885:0x3ffd7f50 in abort at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/panic.c:707
  #2  0x40188863:0x3ffd7f70 in __cxxabiv1::__terminate(void (*)()) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc:112
  #3  0x401888aa:0x3ffd7f90 in std::terminate() at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_terminate.cc:112
  #4  0x401883e9:0x3ffd7fb0 in __cxa_allocate_exception at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/eh_alloc.cc:313
  #5  0x4018813c:0x3ffd7fd0 in operator new(unsigned int) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/new_op.cc:54
  #6  0x401880e9:0x3ffd7ff0 in operator new[](unsigned int) at /builds/idf/crosstool-NG/.build/src/gcc-5.2.0/libstdc++-v3/libsupc++/new_opv.cc:32
  #7  0x40110bcf:0x3ffd8010 in xbuf::addSeg() at .pio\libdeps\lolin_d32\asyncHTTPrequest\src/xbuf.cpp:80
  #8  0x40110c2e:0x3ffd8030 in xbuf::write(unsigned char const*, unsigned int) at .pio\libdeps\lolin_d32\asyncHTTPrequest\src/xbuf.cpp:80
  #9  0x401107c1:0x3ffd8050 in asyncHTTPrequest::_onData(void*, unsigned int) at .pio\libdeps\lolin_d32\asyncHTTPrequest\src/asyncHTTPrequest.cpp:187
  #10 0x401108ed:0x3ffd8070 in std::_Function_handler<void (void*, AsyncClient*, void*, unsigned int), asyncHTTPrequest::_onConnect(AsyncClient*)::{lambda(void*, AsyncClient*, void*, unsigned int)#2}>::_M_invoke(std::_Any_data const&, void*&&, AsyncClient*&&, std::_Any_data const&, unsigned int&&) at .pio\libdeps\lolin_d32\asyncHTTPrequest\src/asyncHTTPrequest.cpp:187
      (inlined by) _M_invoke at c:\users\xxxx\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\5.2.0/functional:1871
  #11 0x40189e91:0x3ffd8090 in std::function<void (void*, AsyncClient*, void*, unsigned int)>::operator()(void*, AsyncClient*, void*, unsigned int) const at .pio\libdeps\lolin_d32\AsyncTCP\src/AsyncTCP.cpp:1116
  #12 0x40189ee5:0x3ffd80c0 in AsyncClient::_recv(tcp_pcb*, pbuf*, signed char) at .pio\libdeps\lolin_d32\AsyncTCP\src/AsyncTCP.cpp:1116
  #13 0x40189f29:0x3ffd80e0 in AsyncClient::_s_recv(void*, tcp_pcb*, pbuf*, signed char) at .pio\libdeps\lolin_d32\AsyncTCP\src/AsyncTCP.cpp:1116
  #14 0x4018a036:0x3ffd8100 in _handle_async_event(lwip_event_packet_t*) at .pio\libdeps\lolin_d32\AsyncTCP\src/AsyncTCP.cpp:1116
  #15 0x4018a105:0x3ffd8120 in _async_service_task(void*) at .pio\libdeps\lolin_d32\AsyncTCP\src/AsyncTCP.cpp:1116
  #16 0x40088c11:0x3ffd8150 in vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c:355 (discriminator 1)
Rebooting...

The function where it was rasied was:

  #10 0x401108ed:0x3ffd8070 in std::_Function_handler<void (void*, AsyncClient*, void*, unsigned int), asyncHTTPrequest::_onConnect(AsyncClient*)::{lambda(void*, AsyncClient*, void*, unsigned int)#2}>::_M_invoke(std::_Any_data const&, void*&&, AsyncClient*&&, std::_Any_data const&, unsigned int&&) at .pio\libdeps\lolin_d32\asyncHTTPrequest\src/asyncHTTPrequest.cpp:187

With debug turned on, I can see it receiving the lines till it eventually crashes.

Is there any way to maybe add a flag to "ignore body?"

Question: Identifying Caller in Callback

I set a callback with onData() and then process the return in the callback. I have more than one method calling asynch events and I was wondering if there's a good way to identify the method which set the callback?

Is JSON supported as response?

I'm trying to GET response from a firebase cloud functions and at the moment I'm using JSON in my entire application (https://us-central1-culltive.cloudfunctions.net/api/devices).

I just copied your sample app and modified the html to the one listed above but had no success.

This is what I get on debug:
Debug(4930): setDebug(on) version 1.1.15
Debug(14931): open(GET, https://us-central1-culltive.clo)
Debug( 1): send()
Debug( 1): _buildRequest()

Exception (28):
epc1=0x4000bf80 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

ESP32 Store prohibited while reading file data from get response of HTTP

I am getting a OTA file from server and trying update the firmware but when i don't know how to get the data successfully in buffer. I tried with ESPAsynWebServer in that case there also they are creating a pointer argument and pushing the data whatever they received and it is getting uploaded successfully. File Size-825KB

What could be the issue?

void requestCB(void* optParm, asyncHTTPrequest* request, int readyState){
if(readyState == 4){
uint8_t data;
size_t len = request->responseLength();
request->responseRead(data,len);
//Serial.println(request->responseText());
Serial.println(request->responseLength());
if (!Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH)) { // Start with max available size
Update.printError(Serial);
}
// if (upload.status == UPLOAD_FILE_START) {
// Serial.printf("Update: %s\n", upload.filename.c_str());
// if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
// Update.printError(Serial);
// }
// } else if (upload.status == UPLOAD_FILE_WRITE) {
/
flashing firmware to ESP*/
if (Update.write(data, len) != len) {
Update.printError(Serial);
}
request->setDebug(false);
}
}

ESP32 compatibility

Hi!
Thanks for the lib and the work you make.

I'm trying to use it on ESP32, i see on code that ESPAsyncTCP is a dependency but it's for ESP8266 and the ESP32 have to use AsyncTCP

I try to make something directly on my own lib but without success.

There is any chance you make it compatible with ESP32 in future?

Fatal Exception 28

Got a fatal exception with a LOLIN D1 MINI.

................................. CONNECTED !
Debug(10376): setDebug(on)
Debug(10377): open(GET, worldtimeapi.org/api/timezone/Eu)
Debug(  1): _parseURL() HTTP://worldtimeapi.org:80/api/timezone/Europe/Zurich.txt
Debug( 57): _connect()
Debug( 82): send()
Debug(102): _buildRequest()
Debug(133): _send() 94
Debug(158): *client not connected
Debug(194): *can't send
Debug(279): _onConnect handler
Debug(280): _setReadyState(1)
Debug(286): _send() 94
Debug(311): *sent 94
Debug(389): _onData handler HTTP/1.1 200 OK
... (536)
Debug(391): _collectHeaders()
Debug(426): _setReadyState(2)
Debug(456): _setReadyState(3)
Debug(490): _onData handler :00:00+00:00
raw... (156)
Debug(545): *all data received - no disconnect
Debug(595): _setReadyState(4)
Debug(627): responseText() Debug(657): responseText() abbreviation: CE... (361)
abbreviation: CEST
client_ip: 62.2.145.206
datetime: 2019-08-14T15:53:20.600738+02:00
day_of_week: 3
day_of_year: 226
dst: true
dst_from: 2019-03-31T01:00:00+00:00
dst_offset: 3600
dst_until: 2019-10-27T01:00:00+00:00
raw_offset: 3600
timezone: Europe/Zurich
unixtime: 1565790800
utc_datetime: 2019-08-14T13:53:20.600738+00:00
utc_offset: +02:00
week_number: 33
Debug(1090): setDebug(off)
FULL_LOCK
1#2019-8-14T15:53:20

Exception (28):
epc1=0x402045de epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffdc0 end: 3fffffc0 offset: 01a0
3fffff60:  3ffe8667 3ffee5d0 4010033e 3ffee8cc  
3fffff70:  3fffdad0 00000000 3ffee5f8 4020482b  
3fffff80:  3fffdad0 00000000 3ffee5f8 40201471  
3fffff90:  3fffdad0 00000000 3ffee89c 402014d7  
3fffffa0:  3fffdad0 00000000 3ffee89c 4020814c  
3fffffb0:  feefeffe feefeffe 3ffe854c 40100931  
<<<stack<<<

Decoded :

Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
PC: 0x402045de: asyncHTTPrequest::_buildRequest() at /home/legrems/Arduino/libraries/asyncHTTPrequest-master/asyncHTTPrequest.cpp line 301
EXCVADDR: 0x00000000

Decoding stack results
0x4010033e: millis() at /home/legrems/.arduino15/packages/esp8266/hardware/esp8266/2.5.2/cores/esp8266/core_esp8266_wiring.cpp line 186
0x4020482b: asyncHTTPrequest::send() at /home/legrems/    _request->write(_URL->scheme);/libraries/asyncHTTPrequest-master/asyncHTTPrequest.cpp line 112
0x40201471: mode_update() at /home/legrems/Documents/*/arduino/arduino.ino line 649
0x402014d7: loop() at /home/legrems/Documents/*/arduino/arduino.ino line 810
0x4020814c: loop_wrapper() at /home/legrems/.arduino15/packages/esp8266/hardware/esp8266/2.5.2/cores/esp8266/core_esp8266_main.cpp line 125

On : _request->write(_URL->scheme); in asyncHTTPrequest.cpp

The first request appear in the setup(), and the second one is in the loop() function after xxxx ms.

a complete working example

hi, any change to have a complete and working and compiling example with post, get and everything it's expected, to have a preview of the lib?

Compilation error on esp32

Hi, I have that compilation error when trying to integrate asyncHTTPRequest to my project for an esp32:

libraries/asyncHTTPrequest/asyncHTTPrequest.cpp.o:(.literal._ZN16asyncHTTPrequest8_connectEv+0x28): undefined reference to `AsyncClient::AsyncClient(tcp_pcb*, tcp_pcb*)'
libraries/asyncHTTPrequest/asyncHTTPrequest.cpp.o:(.literal._ZN16asyncHTTPrequest8_connectEv+0x2c): undefined reference to `AsyncClient::connect(char const*, unsigned short, bool)'
libraries/asyncHTTPrequest/asyncHTTPrequest.cpp.o: In function `asyncHTTPrequest::_connect()':
/Documents/Arduino/libraries/asyncHTTPrequest/src/asyncHTTPrequest.cpp:187: undefined reference to `AsyncClient::AsyncClient(tcp_pcb*, tcp_pcb*)'
/Documents/Arduino/libraries/asyncHTTPrequest/src/asyncHTTPrequest.cpp:187: undefined reference to `AsyncClient::connect(char const*, unsigned short, bool)'

I'm using the AsyncTCP library without any issue as the server running in my project is async. So I don't get why AsyncClient would be undefined. I'm using vscode as IDE.
any help much appreciated :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.